Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/thirdpin/pastilda.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorthirdpin <n_lazareva@mail.ru>2016-08-26 15:13:50 +0300
committerthirdpin <n_lazareva@mail.ru>2016-08-26 15:13:50 +0300
commit5f0b82f2f94fa196fe7222efcd97255db702712a (patch)
tree7bd18d4937caf0d85014b0f70a5c545a58d7e60c
parent44a4f5bae51898b45f3bccbea4788894c2391842 (diff)
version 0.1
-rw-r--r--README.md62
-rw-r--r--emb/pastilda/.cproject43
-rw-r--r--emb/pastilda/.settings/language.settings.xml2
-rw-r--r--emb/pastilda/app/app.cpp89
-rw-r--r--emb/pastilda/app/app.h37
-rw-r--r--emb/pastilda/database/DbEntry.cpp86
-rw-r--r--emb/pastilda/database/DbEntry.h93
-rw-r--r--emb/pastilda/database/xmltree/XmlTree.cpp268
-rw-r--r--emb/pastilda/database/xmltree/XmlTree.h155
-rw-r--r--emb/pastilda/flash/drv/SST25.cpp240
-rw-r--r--emb/pastilda/flash/flash_memory.cpp218
-rw-r--r--emb/pastilda/flash/flash_memory.h102
-rw-r--r--emb/pastilda/fs/drv/SST25.cpp368
-rw-r--r--emb/pastilda/fs/drv/SST25.h (renamed from emb/pastilda/flash/drv/SST25.h)82
-rw-r--r--emb/pastilda/fs/fatfs/diskio.cpp101
-rw-r--r--emb/pastilda/fs/fatfs/diskio.h77
-rw-r--r--emb/pastilda/fs/fatfs/ff.cpp4635
-rw-r--r--emb/pastilda/fs/fatfs/ff.h342
-rw-r--r--emb/pastilda/fs/fatfs/ffconf.h271
-rw-r--r--emb/pastilda/fs/fatfs/integer.h33
-rw-r--r--emb/pastilda/fs/fatfs/option/syscall.c151
-rw-r--r--emb/pastilda/fs/fatfs/option/unicode.c17
-rw-r--r--emb/pastilda/fs/file_system.cpp239
-rw-r--r--emb/pastilda/fs/file_system.h64
-rw-r--r--emb/pastilda/fs/file_system_defines.h161
-rw-r--r--emb/pastilda/keepass/keepass_crypto.cpp87
-rw-r--r--emb/pastilda/keepass/keepass_crypto.h50
-rw-r--r--emb/pastilda/keepass/keepass_reader.cpp270
-rw-r--r--emb/pastilda/keepass/keepass_reader.h75
-rw-r--r--emb/pastilda/keepass/keepass_reader_defines.h92
-rw-r--r--emb/pastilda/keyboard.h237
-rw-r--r--emb/pastilda/keys/AsciiKeyCodes.h169
-rw-r--r--emb/pastilda/keys/Key.cpp653
-rw-r--r--emb/pastilda/keys/Key.h155
-rw-r--r--emb/pastilda/keys/UsbKeyCodes.h354
-rw-r--r--emb/pastilda/leds/leds.cpp (renamed from emb/pastilda/app/leds.cpp)25
-rw-r--r--emb/pastilda/leds/leds.h (renamed from emb/pastilda/app/leds.h)12
-rw-r--r--emb/pastilda/lib/crypto/base64.h255
-rw-r--r--emb/pastilda/lib/crypto/bitops.h294
-rw-r--r--emb/pastilda/lib/crypto/blockwise.c194
-rw-r--r--emb/pastilda/lib/crypto/blockwise.h147
-rw-r--r--emb/pastilda/lib/crypto/chash.c28
-rw-r--r--emb/pastilda/lib/crypto/chash.h137
-rw-r--r--emb/pastilda/lib/crypto/handy.h86
-rw-r--r--emb/pastilda/lib/crypto/salsa20.h111
-rw-r--r--emb/pastilda/lib/crypto/salsa20.inl156
-rw-r--r--emb/pastilda/lib/crypto/sha2.h235
-rw-r--r--emb/pastilda/lib/crypto/sha256.c230
-rw-r--r--emb/pastilda/lib/crypto/tassert.h32
-rw-r--r--emb/pastilda/lib/fastdelegate/FastDelegate.h2109
-rw-r--r--emb/pastilda/lib/fastdelegate/FastDelegateBind.h243
m---------emb/pastilda/lib/libopencm3_cpp_extensions0
-rw-r--r--emb/pastilda/lib/libopenfat/bpb.h146
-rw-r--r--emb/pastilda/lib/libopenfat/direntry.c237
-rw-r--r--emb/pastilda/lib/libopenfat/direntry.h62
-rw-r--r--emb/pastilda/lib/libopenfat/fat_core.c231
-rw-r--r--emb/pastilda/lib/libopenfat/fat_core.h108
-rw-r--r--emb/pastilda/lib/libopenfat/mbr.c71
-rw-r--r--emb/pastilda/lib/libopenfat/openfat.h220
-rw-r--r--emb/pastilda/lib/libopenfat/openfat/blockdev.h76
-rw-r--r--emb/pastilda/lib/libopenfat/openfat/leaccess.h67
-rw-r--r--emb/pastilda/lib/libopenfat/openfat/mbr.h64
-rw-r--r--emb/pastilda/lib/libopenfat/openfat/unixlike.h47
-rw-r--r--emb/pastilda/lib/libopenfat/unixlike.c105
-rw-r--r--emb/pastilda/lib/libopenfat/write.c453
-rw-r--r--emb/pastilda/lib/miniXML/config.h95
-rw-r--r--emb/pastilda/lib/miniXML/mxml-attr.c314
-rw-r--r--emb/pastilda/lib/miniXML/mxml-entity.c449
-rw-r--r--emb/pastilda/lib/miniXML/mxml-file.c3071
-rw-r--r--emb/pastilda/lib/miniXML/mxml-get.c452
-rw-r--r--emb/pastilda/lib/miniXML/mxml-index.c659
-rw-r--r--emb/pastilda/lib/miniXML/mxml-node.c842
-rw-r--r--emb/pastilda/lib/miniXML/mxml-private.c323
-rw-r--r--emb/pastilda/lib/miniXML/mxml-private.h50
-rw-r--r--emb/pastilda/lib/miniXML/mxml-search.c280
-rw-r--r--emb/pastilda/lib/miniXML/mxml-set.c337
-rw-r--r--emb/pastilda/lib/miniXML/mxml-string.c469
-rw-r--r--emb/pastilda/lib/miniXML/mxml.h332
-rw-r--r--emb/pastilda/menu/KeyboardLikeInput.hpp201
-rw-r--r--emb/pastilda/menu/Menu.hpp183
-rw-r--r--emb/pastilda/menu/TildaLogic.cpp511
-rw-r--r--emb/pastilda/menu/TildaLogic.h208
-rw-r--r--emb/pastilda/menu/UsbPackageFactory.cpp252
-rw-r--r--emb/pastilda/menu/UsbPackageFactory.h90
-rw-r--r--emb/pastilda/tree/Tree.hpp272
-rw-r--r--emb/pastilda/tree/TreeNode.hpp225
-rw-r--r--emb/pastilda/usb/usb_device/usb_deque.h86
-rw-r--r--emb/pastilda/usb/usb_device/usb_package.h88
-rw-r--r--emb/pastilda/usb/usb_device/usbd_composite.cpp91
-rw-r--r--emb/pastilda/usb/usb_device/usbd_composite.h55
-rw-r--r--emb/pastilda/usb/usb_device/usbd_composite_desc.cpp7
-rw-r--r--emb/pastilda/usb/usb_device/usbd_composite_desc.h184
-rw-r--r--emb/pastilda/usb/usb_host/usbh_host.cpp20
-rw-r--r--emb/pastilda/usb/usb_host/usbh_host.h13
-rw-r--r--lib/etl/algorithm.h474
-rw-r--r--lib/etl/alignment.h193
-rw-r--r--lib/etl/array.h478
-rw-r--r--lib/etl/basic_string.h141
-rw-r--r--lib/etl/binary.h822
-rw-r--r--lib/etl/bitset.h344
-rw-r--r--lib/etl/bloom_filter.h189
-rw-r--r--lib/etl/char_traits.h243
-rw-r--r--lib/etl/checksum.h200
-rw-r--r--lib/etl/container.h297
-rw-r--r--lib/etl/crc16.cpp58
-rw-r--r--lib/etl/crc16.h108
-rw-r--r--lib/etl/crc16_ccitt.cpp58
-rw-r--r--lib/etl/crc16_ccitt.h108
-rw-r--r--lib/etl/crc16_kermit.cpp58
-rw-r--r--lib/etl/crc16_kermit.h108
-rw-r--r--lib/etl/crc32.cpp74
-rw-r--r--lib/etl/crc32.h108
-rw-r--r--lib/etl/crc64_ecma.cpp106
-rw-r--r--lib/etl/crc64_ecma.h108
-rw-r--r--lib/etl/crc8_ccitt.cpp58
-rw-r--r--lib/etl/crc8_ccitt.h108
-rw-r--r--lib/etl/cyclic_value.h300
-rw-r--r--lib/etl/debounce.h488
-rw-r--r--lib/etl/deque.h140
-rw-r--r--lib/etl/doxygen.h55
-rw-r--r--lib/etl/endian.h91
-rw-r--r--lib/etl/enum_type.h116
-rw-r--r--lib/etl/error_handler.cpp59
-rw-r--r--lib/etl/error_handler.h133
-rw-r--r--lib/etl/etl_arduino.h8
-rw-r--r--lib/etl/exception.h114
-rw-r--r--lib/etl/factorial.h63
-rw-r--r--lib/etl/fibonacci.h72
-rw-r--r--lib/etl/file_error_numbers.txt26
-rw-r--r--lib/etl/fixed_iterator.h268
-rw-r--r--lib/etl/flat_map.h115
-rw-r--r--lib/etl/flat_multimap.h115
-rw-r--r--lib/etl/flat_multiset.h114
-rw-r--r--lib/etl/flat_set.h114
-rw-r--r--lib/etl/fnv_1.h427
-rw-r--r--lib/etl/forward_list.h125
-rw-r--r--lib/etl/frame_check_sequence.h133
-rw-r--r--lib/etl/function.h223
-rw-r--r--lib/etl/functional.h109
-rw-r--r--lib/etl/hash.h401
-rw-r--r--lib/etl/ibasic_string.h2030
-rw-r--r--lib/etl/ibitset.h712
-rw-r--r--lib/etl/ideque.h1465
-rw-r--r--lib/etl/iflat_map.h581
-rw-r--r--lib/etl/iflat_multimap.h530
-rw-r--r--lib/etl/iflat_multiset.h502
-rw-r--r--lib/etl/iflat_set.h508
-rw-r--r--lib/etl/iforward_list.h1055
-rw-r--r--lib/etl/ihash.h80
-rw-r--r--lib/etl/ilist.h1207
-rw-r--r--lib/etl/imap.h1691
-rw-r--r--lib/etl/imultimap.h1424
-rw-r--r--lib/etl/imultiset.h1405
-rw-r--r--lib/etl/instance_count.h83
-rw-r--r--lib/etl/integral_limits.h209
-rw-r--r--lib/etl/intrusive_forward_list.h1169
-rw-r--r--lib/etl/intrusive_links.h827
-rw-r--r--lib/etl/intrusive_list.h1213
-rw-r--r--lib/etl/io_port.h493
-rw-r--r--lib/etl/ipool.h522
-rw-r--r--lib/etl/ipriority_queue.h275
-rw-r--r--lib/etl/iqueue.h225
-rw-r--r--lib/etl/iset.h1622
-rw-r--r--lib/etl/istack.h197
-rw-r--r--lib/etl/iunordered_map.h1271
-rw-r--r--lib/etl/iunordered_multimap.h1191
-rw-r--r--lib/etl/iunordered_multiset.h1183
-rw-r--r--lib/etl/iunordered_set.h1157
-rw-r--r--lib/etl/ivector.h907
-rw-r--r--lib/etl/jenkins.h168
-rw-r--r--lib/etl/largest.h168
-rw-r--r--lib/etl/list.h137
-rw-r--r--lib/etl/log.h113
-rw-r--r--lib/etl/map.h113
-rw-r--r--lib/etl/multimap.h112
-rw-r--r--lib/etl/multiset.h112
-rw-r--r--lib/etl/murmur3.h235
-rw-r--r--lib/etl/nullptr.h116
-rw-r--r--lib/etl/numeric.h58
-rw-r--r--lib/etl/observer.h348
-rw-r--r--lib/etl/optional.h442
-rw-r--r--lib/etl/parameter_type.h63
-rw-r--r--lib/etl/pearson.cpp58
-rw-r--r--lib/etl/pearson.h165
-rw-r--r--lib/etl/platform.h73
-rw-r--r--lib/etl/pool.h91
-rw-r--r--lib/etl/power.h185
-rw-r--r--lib/etl/priority_queue.h115
-rw-r--r--lib/etl/private/deque_base.h179
-rw-r--r--lib/etl/private/flat_map_base.h171
-rw-r--r--lib/etl/private/flat_multimap_base.h155
-rw-r--r--lib/etl/private/flat_multiset_base.h157
-rw-r--r--lib/etl/private/flat_set_base.h171
-rw-r--r--lib/etl/private/forward_list_base.h264
-rw-r--r--lib/etl/private/ivectorpointer.h528
-rw-r--r--lib/etl/private/list_base.h299
-rw-r--r--lib/etl/private/map_base.h427
-rw-r--r--lib/etl/private/multimap_base.h586
-rw-r--r--lib/etl/private/multiset_base.h587
-rw-r--r--lib/etl/private/pool_base.h159
-rw-r--r--lib/etl/private/pvoidvector.h627
-rw-r--r--lib/etl/private/queue_base.h165
-rw-r--r--lib/etl/private/set_base.h427
-rw-r--r--lib/etl/private/stack_base.h163
-rw-r--r--lib/etl/private/string_base.h217
-rw-r--r--lib/etl/private/vector_base.h185
-rw-r--r--lib/etl/queue.h108
-rw-r--r--lib/etl/radix.h66
-rw-r--r--lib/etl/set.h113
-rw-r--r--lib/etl/smallest.h179
-rw-r--r--lib/etl/stack.h109
-rw-r--r--lib/etl/static_assert.h53
-rw-r--r--lib/etl/string.h189
-rw-r--r--lib/etl/type_def.h293
-rw-r--r--lib/etl/type_traits.h371
-rw-r--r--lib/etl/u16string.h189
-rw-r--r--lib/etl/u32string.h189
-rw-r--r--lib/etl/unordered_map.h123
-rw-r--r--lib/etl/unordered_multimap.h123
-rw-r--r--lib/etl/unordered_multiset.h123
-rw-r--r--lib/etl/unordered_set.h123
-rw-r--r--lib/etl/variant.h935
-rw-r--r--lib/etl/vector.h223
-rw-r--r--lib/etl/visitor.h462
-rw-r--r--lib/etl/wstring.h190
m---------lib/libopencm30
226 files changed, 69942 insertions, 2960 deletions
diff --git a/README.md b/README.md
index 773f9c7..55997d8 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,61 @@
-# PASTILDA - open source password manager
+# PASTILDA: open-source password manager
+
+DESCRIPTION
+
+It is an open-source hardware designed to manage our credentials in handy and secure way. It provides easy and safe auto-login to bank accounts, mailboxes, corporate network or social media.
+
+So if you also have to daily remember and enter a number of strong passwords — assign it to Pastilda.
+
+Pastilda never reveals master key to the host. Decrypted data stays onboard, unreachable for malware.
+
+Requires no drivers or client software. Pastilda impersonates a common keyboard, so it works with most systems by default.
+
+Summon a control menu to any text field.
+
+Applicable for command line interfaces.
+
+COMPLETE OPENNESS
+
+Publishes under GNU GPL license. Feel free to use both software and hardware in your own projects.
+
+
+HOW DOES IT WORK
+
+Pastilda has two USB slots: one to connect keyboard, one to connect it to your PC. So, your OS recognize Pastilda as composite device: keyboard and flash drive. And your real keyboard now is visible just for Pastilda, your PC doesn't see it at all.
+
+On flash drive you have to store KeePass 2.x portable and encrypted database (.kdbx file).
+
+In a regular mode, everyting you type on you keyboard translates through Pastilda to your PC.
+
+If you need to sign in to social media for example, you need to switch to "Pastilda mode". To do that you have to set your mouse cursor inside a login textbox and then type combination Ctrl + ~. After that, Pastilda will ask you to enter password from your KeePass database.
+
+If password is correct Pastilda decrypts your database and you can start to navigate trough it with arrows left, right, up and down. As soon as you find the login you were looking for, you should type Enter and after that, Pastilda automaticly substitutes the corresponding password in password textbox and enters you account.
+
+If password is incorrect Pastilda will offer you to enter password again. So, you can either continue to enter password or go back to regular mode by pressing Esc key on your keyboard.
+
+WHAT IS DONE FOR NOW
+
+We have finished prototyping and released version 0.1. We have implemented just the basic functionality by now, so there are few limitations:
+
+1. Pastilda can't handle media keyboards.
+2. You can load just up to 30Kb database.
+3. When you load KeePass 2.x database to the flash drive, you have to change extension from .kdbx to .kdb.
+4. You have to disable GZip compression in KeePass 2.x application.
+
+HOW TO BUILD
+
+We are using Eclipse + GNU ARM Eclipse + OpenOCD. You can read about it here: http://gnuarmeclipse.github.io.
+
+When you fork or clone the repository, you have to add two submodules:
+
+1. libopencm3 to folder /lib (use this fork: https://github.com/thirdpin/libopencm3).
+2. libopencm3_cpp_extensions to folder /emb/pastilda/lib (available here: https://github.com/thirdpin/libopencm3_cpp_extensions).
+
+CONTACTS
+
+If you have any questions, please feel free to contact us:
+Anastasiia Lazareva: a.lazareva@thirdpin.ru
+Сorporate e-mail: info@ThirdPin.ru
+
+
+
diff --git a/emb/pastilda/.cproject b/emb/pastilda/.cproject
index 5b58df7..846b4cc 100644
--- a/emb/pastilda/.cproject
+++ b/emb/pastilda/.cproject
@@ -54,16 +54,28 @@
<listOptionValue builtIn="false" value="USE_STM32F4_USBH_DRIVER_HS"/>
</option>
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.include.paths.1095580488" name="Include paths (-I)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.include.paths" useByScannerDiscovery="false" valueType="includePath">
+ <listOptionValue builtIn="false" value="&quot;../../../lib&quot;"/>
<listOptionValue builtIn="false" value="&quot;../..\..\lib\libopencm3\include&quot;"/>
<listOptionValue builtIn="false" value="&quot;../..\..\lib\libopencm3\lib&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/app}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/database}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/database/xmltree}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/fs}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/fs/drv}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/fs/fatfs}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/keepass}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/keys}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/leds}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/lib/crypto}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/lib/fastdelegate}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/lib/libopencm3_cpp_extensions}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/lib/libusbhost}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/lib/miniXML}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/menu}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/tree}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/usb/usb_device}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/usb/usb_host}&quot;"/>
- <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/lib/libusbhost}&quot;"/>
- <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/lib/libopenfat/openfat}&quot;"/>
- <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/lib/libopenfat}&quot;"/>
- <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/lib/libopencm3_cpp_extensions}&quot;"/>
</option>
<inputType id="ilg.gnuarmeclipse.managedbuild.cross.tool.c.compiler.input.338584563" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.c.compiler.input"/>
</tool>
@@ -73,19 +85,30 @@
<listOptionValue builtIn="false" value="USE_STM32F4_USBH_DRIVER_HS"/>
</option>
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.include.paths.1410012800" name="Include paths (-I)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.include.paths" useByScannerDiscovery="false" valueType="includePath">
+ <listOptionValue builtIn="false" value="&quot;../../../lib&quot;"/>
<listOptionValue builtIn="false" value="&quot;../..\..\lib\libopencm3\include&quot;"/>
<listOptionValue builtIn="false" value="&quot;../..\..\lib\libopencm3\lib&quot;"/>
- <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/flash/drv}&quot;"/>
- <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/flash}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/app}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/database/xmltree}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/database}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/fs}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/fs/drv}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/fs/fatfs}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/keepass}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/keys}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/leds}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/lib/crypto}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/lib/fastdelegate}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/lib/libopencm3_cpp_extensions}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/lib/libusbhost}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/lib/miniXML}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/menu}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/tree}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/usb/usb_device}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/usb/usb_host}&quot;"/>
- <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/lib/libusbhost}&quot;"/>
- <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/lib/libopenfat}&quot;"/>
- <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/lib/libopenfat/openfat}&quot;"/>
- <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/lib/libopencm3_cpp_extensions}&quot;"/>
</option>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.std.931848984" name="Language standard" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.std" useByScannerDiscovery="true" value="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.std.cpp1y" valueType="enumerated"/>
<inputType id="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.compiler.input.583307617" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.compiler.input"/>
</tool>
<tool id="ilg.gnuarmeclipse.managedbuild.cross.tool.c.linker.1932922195" name="Cross ARM C Linker" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.c.linker">
diff --git a/emb/pastilda/.settings/language.settings.xml b/emb/pastilda/.settings/language.settings.xml
index b82979e..7067f14 100644
--- a/emb/pastilda/.settings/language.settings.xml
+++ b/emb/pastilda/.settings/language.settings.xml
@@ -5,7 +5,7 @@
<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
- <provider class="org.eclipse.cdt.managedbuilder.language.settings.providers.GCCBuiltinSpecsDetector" console="false" env-hash="228017701990115227" id="ilg.gnuarmeclipse.managedbuild.cross.GCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT GCC Built-in Compiler Settings Cross ARM" parameter="${COMMAND} ${FLAGS} ${cross_toolchain_flags} -E -P -v -dD &quot;${INPUTS}&quot;" prefer-non-shared="true">
+ <provider class="org.eclipse.cdt.managedbuilder.language.settings.providers.GCCBuiltinSpecsDetector" console="false" env-hash="228019831546369560" id="ilg.gnuarmeclipse.managedbuild.cross.GCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT GCC Built-in Compiler Settings Cross ARM" parameter="${COMMAND} ${FLAGS} ${cross_toolchain_flags} -E -P -v -dD &quot;${INPUTS}&quot;" prefer-non-shared="true">
<language-scope id="org.eclipse.cdt.core.gcc"/>
<language-scope id="org.eclipse.cdt.core.g++"/>
</provider>
diff --git a/emb/pastilda/app/app.cpp b/emb/pastilda/app/app.cpp
index 8ea95f3..8a67ab5 100644
--- a/emb/pastilda/app/app.cpp
+++ b/emb/pastilda/app/app.cpp
@@ -3,7 +3,10 @@
* hosted at http://github.com/thirdpin/pastilda
*
* Copyright (C) 2016 Third Pin LLC
- * Written by Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ *
+ * Written by:
+ * Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ * Dmitrii Lisin <mrlisdim@ya.ru>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,9 +22,19 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <cstdio>
+
+#include <FastDelegate.h>
+#include <libopencmsis/core_cm3.h>
+
#include "app.h"
-#include "stdio.h"
+
+using namespace std::placeholders;
+
using namespace Application;
+using namespace Keys;
+
+namespace fastdeligate = fd;
App *app_pointer;
@@ -29,57 +42,37 @@ App::App()
{
app_pointer = this;
- clock_setup();
- systick_init();
+ scb_set_priority_grouping(SCB_AIRCR_PRIGROUP_GROUP2_SUB8);
- _leds_api = new LEDS_api();
- _flash = new FlashMemory();
- usb_host = new USB_host(redirect, control_interception);
- usb_composite = new USB_composite(_flash->flash_blocks(), _flash->flash_read, _flash->flash_write);
-}
-void App::process()
-{
- _leds_api->toggle();
- usb_host->poll();
+ _fs = new FileSystem();
+
+ _usb_composite = new USB_composite(UsbMemoryControlParams { _fs->msd_blocks(),
+ _fs->msd_read,
+ _fs->msd_write });
+
+ Logic::TildaLogic::SpecialPoints specialMenuPoints {
+ {
+ "Format flash",
+ std::strlen("Format flash\0"),
+ fd::MakeDelegate(_fs, &FileSystem::format_to_FAT12)
+ }
+ };
+ _tildaLogic = new Logic::TildaLogic(_usb_composite->get_usb_deque(),
+ specialMenuPoints);
+
+ _usb_host = new USB_host(host_keyboard_callback);
+ // TODO: fix it
+ delay_ms(6000); // wait usb device initializing
+ _usb_composite->init_hid_interrupt();
}
-void App::redirect(uint8_t *data, uint8_t len)
+void App::process()
{
- app_pointer->usb_composite->usb_send_packet(data, len);
+ _leds_api.toggle();
+ _usb_host->poll();
}
-void App::control_interception()
+void App::host_keyboard_callback(uint8_t *data, uint8_t len)
{
- memset(app_pointer->key, 0, 8);
- app_pointer->key[2] = KEY_W;
- app_pointer->key[3] = KEY_O;
- app_pointer->key[4] = KEY_N;
- app_pointer->key[5] = KEY_D;
- app_pointer->key[6] = KEY_E;
- app_pointer->key[7] = KEY_R;
- app_pointer->usb_composite->usb_send_packet(app_pointer->key, 8);
-
- app_pointer->key[2] = 0;
- app_pointer->key[3] = 0;
- app_pointer->key[4] = 0;
- app_pointer->key[5] = 0;
- app_pointer->key[6] = 0;
- app_pointer->key[7] = 0;
- app_pointer->usb_composite->usb_send_packet(app_pointer->key, 8);
-
- app_pointer->key[2] = KEY_SPACEBAR;
- app_pointer->key[3] = KEY_W;
- app_pointer->key[4] = KEY_O;
- app_pointer->key[5] = KEY_M;
- app_pointer->key[6] = KEY_A;
- app_pointer->key[7] = KEY_N;
- app_pointer->usb_composite->usb_send_packet(app_pointer->key, 8);
-
- app_pointer->key[2] = 0;
- app_pointer->key[3] = 0;
- app_pointer->key[4] = 0;
- app_pointer->key[5] = 0;
- app_pointer->key[6] = 0;
- app_pointer->key[7] = 0;
- app_pointer->usb_composite->usb_send_packet(app_pointer->key, 8);
+ app_pointer->_tildaLogic->process(data, len);
}
diff --git a/emb/pastilda/app/app.h b/emb/pastilda/app/app.h
index 6f21d59..e0e6c4a 100644
--- a/emb/pastilda/app/app.h
+++ b/emb/pastilda/app/app.h
@@ -3,7 +3,10 @@
* hosted at http://github.com/thirdpin/pastilda
*
* Copyright (C) 2016 Third Pin LLC
- * Written by Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ *
+ * Written by:
+ * Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ * Dmitrii Lisin <mrlisdim@ya.ru>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,22 +26,17 @@
#define APP_H
#include <string.h>
-#include <usb/usb_device/usbd_composite.h>
-#include <usb/usb_host/usbh_host.h>
+
#include "clock.h"
-#include "gpio_ext.h"
-#include "systick_ext.h"
#include "leds.h"
-#include "flash_memory.h"
-
-extern "C" {
-#include "keyboard.h"
-}
-
+#include "usbd_composite.h"
+#include "usbh_host.h"
+#include "file_system.h"
+#include "menu/TildaLogic.h"
+#include "keepass_reader.h"
using namespace LEDS_API;
-using namespace GPIO_CPP_Extension;
-using namespace SPI_CPP_Extension;
+using namespace KeepAss;
namespace Application
{
@@ -48,15 +46,14 @@ namespace Application
App();
void process();
- static void redirect(uint8_t *data, uint8_t len);
- static void control_interception();
+ static void host_keyboard_callback(uint8_t *data, uint8_t len);
private:
- LEDS_api *_leds_api;
- FlashMemory *_flash;
- USB_composite *usb_composite;
- USB_host *usb_host;
- uint8_t key[8];
+ LEDS_api _leds_api;
+ FileSystem *_fs;
+ USB_composite *_usb_composite;
+ USB_host *_usb_host;
+ Logic::TildaLogic* _tildaLogic;
};
}
#endif
diff --git a/emb/pastilda/database/DbEntry.cpp b/emb/pastilda/database/DbEntry.cpp
new file mode 100644
index 0000000..296cffe
--- /dev/null
+++ b/emb/pastilda/database/DbEntry.cpp
@@ -0,0 +1,86 @@
+/*
+ * This file is part of the pastilda project.
+ * hosted at http://github.com/thirdpin/pastilda
+ *
+ * Copyright (C) 2016 Third Pin LLC
+ *
+ * Written by:
+ * Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ * Dmitrii Lisin <mrlisdim@ya.ru>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <DbEntry.h>
+
+namespace DB {
+
+Entry::Entry() :
+ _index(0),
+ _name(EMPTY_FIELD),
+ _login(EMPTY_FIELD),
+ _password(EMPTY_FIELD),
+ _type(EMPTY_FIELD)
+{ }
+
+Entry::Entry(size_t index) :
+ _index(index),
+ _name(EMPTY_FIELD),
+ _login(EMPTY_FIELD),
+ _password(EMPTY_FIELD),
+ _type(EMPTY_FIELD)
+{ }
+
+Entry::~Entry()
+{ }
+
+Entry::Entry(const Entry& entry)
+{
+ _index = entry.getIndex();
+ _name = entry.getName();
+ _login = entry.getLogin();
+ _password = entry.getPassword();
+ _type = entry.getType();
+}
+
+void Entry::setIndex(uint32_t index)
+{
+ _index = index;
+}
+
+void Entry::setName(const uint8_t* name, size_t length)
+{
+ StringField nameString(name, length);
+ _name.swap(nameString);
+}
+
+void Entry::setLogin(const uint8_t* login, size_t length)
+{
+ StringField loginString(login, length);
+ _login.swap(loginString);
+}
+
+void Entry::setPassword(const uint8_t* password, size_t length)
+{
+ StringField passwordString(password, length);
+ _password.swap(passwordString);
+}
+
+void Entry::setType(const uint8_t* type, size_t length)
+{
+ StringField typeString(type, length);
+ _type.swap(typeString);
+}
+
+}
diff --git a/emb/pastilda/database/DbEntry.h b/emb/pastilda/database/DbEntry.h
new file mode 100644
index 0000000..8976c51
--- /dev/null
+++ b/emb/pastilda/database/DbEntry.h
@@ -0,0 +1,93 @@
+/*
+ * This file is part of the pastilda project.
+ * hosted at http://github.com/thirdpin/pastilda
+ *
+ * Copyright (C) 2016 Third Pin LLC
+ *
+ * Written by:
+ * Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ * Dmitrii Lisin <mrlisdim@ya.ru>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef DATABASE_DBENTRY_H_
+#define DATABASE_DBENTRY_H_
+
+#include <experimental/string_view>
+#include <cstddef>
+#include <cstdint>
+
+using std::size_t;
+using std::experimental::basic_string_view;
+
+namespace DB {
+
+using StringField = basic_string_view<uint8_t>;
+using StringFieldChar = StringField::value_type;
+using StringFieldConst = const StringField;
+
+constexpr static const StringFieldChar* EMPTY_FIELD_CHAR =
+ reinterpret_cast<const StringFieldChar*>("");
+
+constexpr static StringField EMPTY_FIELD(EMPTY_FIELD_CHAR, 1);
+
+class Entry
+{
+public:
+ Entry();
+ Entry(size_t index);
+ ~Entry();
+
+ Entry(const Entry& entry);
+
+ void setIndex(uint32_t index);
+ void setName(const uint8_t* name, size_t length);
+ void setLogin(const uint8_t* login, size_t length);
+ void setPassword(const uint8_t* password, size_t length);
+ void setType(const uint8_t* type, size_t length);
+
+ uint32_t getIndex() const {
+ return _index;
+ }
+
+ StringFieldConst& getLogin() const {
+ return _login;
+ }
+
+ StringFieldConst& getName() const {
+ return _name;
+ }
+
+ StringFieldConst& getPassword() const {
+ return _password;
+ }
+
+ StringFieldConst& getType() const {
+ return _type;
+ }
+
+private:
+ uint32_t _index;
+ StringField _name;
+ StringField _login;
+ StringField _password;
+
+ StringField _type;
+};
+
+} // namespace DB
+
+
+#endif /* DATABASE_DBENTRY_H_ */
diff --git a/emb/pastilda/database/xmltree/XmlTree.cpp b/emb/pastilda/database/xmltree/XmlTree.cpp
new file mode 100644
index 0000000..5de87fa
--- /dev/null
+++ b/emb/pastilda/database/xmltree/XmlTree.cpp
@@ -0,0 +1,268 @@
+/*
+ * This file is part of the pastilda project.
+ * hosted at http://github.com/thirdpin/pastilda
+ *
+ * Copyright (C) 2016 Third Pin LLC
+ *
+ * Written by:
+ * Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ * Dmitrii Lisin <mrlisdim@ya.ru>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+
+#include <etl/string.h>
+
+#include "XmlTree.h"
+
+using std::size_t;
+
+namespace DB {
+
+XmlTree::XmlTree(RawTree tree)
+{
+ init(tree);
+}
+
+XmlTree::XmlTree():
+ _rawTree(nullptr),
+ _currentNode(nullptr)
+{ }
+
+void XmlTree::init(RawTree tree)
+{
+ // Finding the top Group tag (it should be in file)
+ RawNode topNode =
+ mxmlFindElement(tree, tree,
+ _castInChar(TagStrings::GROUP), NULL, NULL,
+ MXML_DESCEND);
+
+ _currentNode = topNode;
+ _rawTree = topNode;
+
+ moveInto(); // avoid top group
+ _updateNodeInfo();
+}
+
+XmlTree::~XmlTree() { }
+
+void XmlTree::moveInto()
+{
+ if (isMostBottom() == false) {
+ RawNode entryNode = _findElement(_currentNode, TagStrings::ENTRY);
+ RawNode groupNode = _findElement(_currentNode, TagStrings::GROUP);
+
+ // Entry nodes are always first in keepass xml file
+ if (entryNode != NULL) {
+ _currentNode = entryNode;
+ }
+ else if (groupNode != NULL) {
+ _currentNode = groupNode;
+ }
+ }
+}
+
+void XmlTree::moveOut()
+{
+ if (isMostTop() == false) {
+ _currentNode = mxmlGetParent(_currentNode);
+ }
+}
+
+void XmlTree::moveLeft()
+{
+ if (isMostLeft() == false) {
+ _currentNode = _getPrev();
+ }
+}
+
+void XmlTree::moveRight()
+{
+ if (isMostRight() == false) {
+ _currentNode = _getNext();
+ }
+}
+
+void XmlTree::moveInHead()
+{
+ _currentNode = _rawTree;
+ moveInto(); // avoid top group
+}
+
+void XmlTree::moveMostLeft()
+{
+ while (isMostLeft() == false) {
+ moveLeft();
+ }
+}
+
+void XmlTree::moveMostRight()
+{
+ while (isMostRight() == false) {
+ moveRight();
+ }
+}
+
+bool XmlTree::isEndNode()
+{
+ _updateNodeInfo();
+ return !_currentNodeStruct.isExpanded;
+}
+
+bool XmlTree::isMostTop()
+{
+ return (mxmlGetParent(_currentNode) == _rawTree);
+}
+
+bool XmlTree::isMostBottom()
+{
+ if (isEndNode() == false) {
+ RawNode entryNode = _findElement(_currentNode, TagStrings::ENTRY);
+ RawNode groupNode = _findElement(_currentNode, TagStrings::GROUP);
+ return (entryNode == NULL && groupNode == NULL);
+ }
+
+ return true;
+}
+
+bool XmlTree::isMostLeft()
+{
+ return (_getPrev() == NULL);
+}
+
+bool XmlTree::isMostRight()
+{
+ return (_getNext() == NULL);
+}
+
+auto XmlTree::_getNext() -> RawNode
+{
+ // We should to mxmlWalkNext() twice,
+ // because min-xml lib working so.
+ RawNode node =
+ mxmlWalkNext(_currentNode, mxmlGetParent(_currentNode), MXML_NO_DESCEND);
+ node =
+ mxmlWalkNext(node, mxmlGetParent(_currentNode), MXML_NO_DESCEND);
+
+ return node;
+}
+
+auto XmlTree::_getPrev() -> RawNode
+{
+ // We should to mxmlWalkPrev() twice,
+ // because min-xml lib working so.
+ RawNode node =
+ mxmlWalkPrev(_currentNode, mxmlGetParent(_currentNode), MXML_NO_DESCEND);
+ node =
+ mxmlWalkPrev(node, mxmlGetParent(_currentNode), MXML_NO_DESCEND);
+
+ // Check if it's Entry or Group
+ const char* tagName = node->value.element.name;
+ if (std::strcmp(tagName, _castInChar(TagStrings::ENTRY)) == 0 ||
+ std::strcmp(tagName, _castInChar(TagStrings::GROUP)) == 0)
+ {
+ return node;
+ }
+
+ return NULL;
+}
+
+void XmlTree::_updateNodeInfo()
+{
+ StringField fieldIsExpanded = _getTextByTag(TagStrings::IS_EXPANDED);
+
+ bool isExpanded = (fieldIsExpanded == StringBool::TRUE);
+ _currentNodeStruct.isExpanded = isExpanded;
+
+ if (isExpanded) { // if <Group>
+ _currentNodeStruct.name = _getTextByTag(TagStrings::NAME);
+ _currentNodeStruct.login =
+ _currentNodeStruct.password =
+ _currentNodeStruct.type = DB::EMPTY_FIELD;
+ }
+ else { // if <Entry>
+ _currentNodeStruct.name = _getKey(KeyStrings::TITLE);
+ _currentNodeStruct.login = _getKey(KeyStrings::USER_NAME);
+ _currentNodeStruct.password = _getKey(KeyStrings::PASSWORD);
+ _currentNodeStruct.type = _getKey(KeyStrings::TYPE);
+ }
+}
+
+StringField XmlTree::_getTextByTag(TagStrings::StringType tagName)
+{
+ RawNode nameNode = _findElement(_currentNode, tagName);
+ if (nameNode == nullptr) {
+ return DB::EMPTY_FIELD;
+ }
+
+ return _getText(nameNode);
+}
+
+auto XmlTree::_findElement(RawNode startNode,
+ TagStrings::StringType elemName) -> RawNode
+{
+ if (startNode == _currentNode) {
+ startNode = _currentNode->child;
+ }
+ return mxmlFindElement(startNode, _currentNode,
+ _castInChar(elemName), NULL, NULL,
+ MXML_NO_DESCEND);
+}
+
+auto XmlTree::_findElementInto(RawNode parentNode,
+ RawNode startNode,
+ TagStrings::StringType elemName) -> RawNode
+{
+ if (startNode == NULL) {
+ startNode = parentNode->child;
+ }
+ return mxmlFindElement(startNode, parentNode,
+ _castInChar(elemName), NULL, NULL,
+ MXML_NO_DESCEND);
+}
+
+StringField XmlTree::_getText(RawNode node)
+{
+ const char* text = mxmlGetOpaque(node);
+ size_t length = etl::strlen(text);
+
+ return StringField(
+ reinterpret_cast<const StringFieldChar*>(text),
+ length
+ );
+}
+
+StringField XmlTree::_getKey(KeyStrings::StringType keyName)
+{
+ for (RawNode stringNode = _findElement(_currentNode, TagStrings::STRING);
+ stringNode != NULL;
+ stringNode = _findElement(stringNode, TagStrings::STRING))
+ {
+ RawNode keyNode = _findElementInto(stringNode, NULL, TagStrings::KEY);
+ StringField keyText = _getText(keyNode);
+ if (keyText == keyName) {
+ RawNode valueNode =
+ _findElementInto(stringNode, keyNode, TagStrings::VALUE);
+ return _getText(valueNode);
+ }
+ }
+
+ return StringField();
+}
+
+}
diff --git a/emb/pastilda/database/xmltree/XmlTree.h b/emb/pastilda/database/xmltree/XmlTree.h
new file mode 100644
index 0000000..877cc61
--- /dev/null
+++ b/emb/pastilda/database/xmltree/XmlTree.h
@@ -0,0 +1,155 @@
+/*
+ * This file is part of the pastilda project.
+ * hosted at http://github.com/thirdpin/pastilda
+ *
+ * Copyright (C) 2016 Third Pin LLC
+ *
+ * Written by:
+ * Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ * Dmitrii Lisin <mrlisdim@ya.ru>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef DATABASE_XMLTREE_XMLTREE_H_
+#define DATABASE_XMLTREE_XMLTREE_H_
+
+extern "C" {
+#include <mxml.h>
+}
+
+#include <DbEntry.h>
+
+namespace DB {
+
+struct StringBool
+{
+ using BoolType = const StringFieldChar*;
+
+ static constexpr BoolType TRUE = reinterpret_cast<BoolType>("True");
+ static constexpr BoolType FALSE = reinterpret_cast<BoolType>("False");
+};
+
+class XmlTree {
+public:
+ using RawTree = mxml_node_t*;
+ using RawNode = mxml_node_t*;
+
+ struct NodeStruct {
+ StringField name;
+ StringField login;
+ StringField password;
+ StringField type;
+ bool isExpanded;
+ };
+
+ XmlTree();
+ XmlTree(RawTree tree);
+ ~XmlTree();
+
+ void init(RawTree tree);
+
+ const NodeStruct& getCurrentNodeInfo() {
+ _updateNodeInfo();
+ return _currentNodeStruct;
+ }
+
+ RawNode getCurrentNode() {
+ return _currentNode;
+ }
+
+ void moveLeft();
+ void moveRight();
+ void moveInto();
+ void moveOut();
+
+ void moveInHead();
+ void moveMostRight();
+ void moveMostLeft();
+
+ bool isMostLeft();
+ bool isMostRight();
+ bool isMostTop();
+ bool isMostBottom();
+ bool isEndNode();
+
+private:
+ struct TagStrings {
+ using StringType = const StringFieldChar*;
+
+ static constexpr StringType IS_EXPANDED =
+ reinterpret_cast<StringType>("IsExpanded");
+
+ static constexpr StringType NAME =
+ reinterpret_cast<StringType>("Name");
+
+ static constexpr StringType STRING =
+ reinterpret_cast<StringType>("String");
+
+ static constexpr StringType KEY =
+ reinterpret_cast<StringType>("Key");
+
+ static constexpr StringType VALUE =
+ reinterpret_cast<StringType>("Value");
+
+ static constexpr StringType ENTRY =
+ reinterpret_cast<StringType>("Entry");
+
+ static constexpr StringType GROUP =
+ reinterpret_cast<StringType>("Group");
+ };
+
+ struct KeyStrings {
+ using StringType = const StringFieldChar*;
+
+ static constexpr StringType TITLE =
+ reinterpret_cast<StringType>("Title");
+
+ static constexpr StringType USER_NAME =
+ reinterpret_cast<StringType>("UserName");
+
+ static constexpr StringType PASSWORD =
+ reinterpret_cast<StringType>("Password");
+
+ static constexpr StringType TYPE =
+ reinterpret_cast<StringType>("Type");
+ };
+
+ RawTree _rawTree;
+ RawNode _currentNode;
+ NodeStruct _currentNodeStruct;
+
+ void _updateNodeInfo();
+
+ RawNode _getNext();
+ RawNode _getPrev();
+
+ StringField _getKey(KeyStrings::StringType keyName);
+ StringField _getTextByTag(TagStrings::StringType tagName);
+ StringField _getText(RawNode node);
+
+ RawNode _findElement(RawNode startNode, TagStrings::StringType elemName);
+ RawNode _findElementInto(RawNode parentNode,
+ RawNode startNode,
+ TagStrings::StringType elemName);
+
+ template<typename T>
+ const char* _castInChar(T str) {
+ return reinterpret_cast<const char*>(str);
+ }
+};
+
+}
+
+#endif /* DATABASE_XMLTREE_XMLTREE_H_ */
diff --git a/emb/pastilda/flash/drv/SST25.cpp b/emb/pastilda/flash/drv/SST25.cpp
deleted file mode 100644
index 954188a..0000000
--- a/emb/pastilda/flash/drv/SST25.cpp
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * This file is part of the pastilda project.
- * hosted at http://github.com/thirdpin/pastilda
- *
- * Copyright (C) 2016 Third Pin LLC
- * Written by Anastasiia Lazareva <a.lazareva@thirdpin.ru>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "SST25.h"
-
-SST25::SST25(SPI_ext *spi, Pinout nss_pin)
-{
- _spi = spi;
-
- _nss = new GPIO_ext(nss_pin);
- _nss->mode_setup(GPIO_CPP_Extension::Mode::OUTPUT, GPIO_CPP_Extension::PullMode::NO_PULL);
- _nss->set_output_options(GPIO_CPP_Extension::OutputType::PUSH_PULL, GPIO_CPP_Extension::Speed::FAST_50MHz);
- _nss->set();
-}
-
-int SST25::read_sectors(uint32_t sector, uint32_t count, void *buf)
-{
- if(sector >= (SECTOR_COUNT)) {
- return (0);
- }
-
- uint32_t address = (sector * SECTOR_SIZE);
- uint32_t data_len = SECTOR_SIZE * count;
-
- while ((address + data_len - 1) > (MEMORY_SIZE - 1)) {
- count -= 1;
- data_len = SECTOR_SIZE * count;
- }
-
- read(address, data_len, (uint8_t*)buf);
- return (count);
-}
-int SST25::write_sectors(uint32_t sector, uint32_t count, const void *buf)
-{
- if(sector >= (SECTOR_COUNT)) {
- return (0);
- }
-
- uint32_t start_address = (sector * SECTOR_SIZE);
- uint32_t data_len = SECTOR_SIZE * count;
-
- for(int i = 0; i < count; i++)
- {
- erase_sector(sector + i);
- uint32_t address = ((sector + i) * SECTOR_SIZE);
-
- for (int j = 0; j < PAGE_COUNT_IN_SECTOR; j++) {
- page_program(address, (uint8_t*)buf, PAGE_SIZE);
- address += PAGE_SIZE;
- buf += PAGE_SIZE;
- }
- }
- return (count);
-}
-void SST25::disable_wtite_protection()
-{
- enable_write_status_register();
- write_status_register(DISABLE_WRITE_PROTECTION);
-}
-
-void SST25::read(uint32_t address, uint32_t count, uint8_t* buf)
-{
- wait_write_complete();
- select_device();
- uint8_t tx[4] = {OPCODE_READ, ((address >> 16) & 0xFF), ((address >> 8) & 0xFF), (address & 0xFF)};
- write_buffer(tx, 4);
- uint8_t rx[count];
- read_buffer(rx, count);
- release_device();
- memcpy(buf, rx, count);
- //return (rx);
-}
-void SST25::read_high_speed(uint32_t address, uint32_t count, uint8_t* buf)
-{
- wait_write_complete();
- select_device();
- uint8_t tx[5] = {OPCODE_FAST_READ, ((address >> 16) & 0xFF), ((address >> 8) & 0xFF), (address & 0xFF), DUMMY_BYTE};
- write_buffer(tx, 5);
- uint8_t rx[count];
- read_buffer(rx, count);
- release_device();
- memcpy(buf, rx, count);
- //return (rx);
-}
-void SST25::page_program(uint32_t address, uint8_t *data, uint16_t count)
-{
- wait_write_complete();
- enable_write();
- select_device();
- uint16_t total_size = (4 + count);
- uint8_t tx[total_size] = {OPCODE_PAGE_PROGRAM, ((address >> 16) & 0xFF), ((address >> 8) & 0xFF), (address & 0xFF)};
- for (int i = 0, j = 4; i < count; i++, j++) {
- tx[j] = data[i];
- }
- write_buffer(tx, total_size);
- release_device();
-}
-void SST25::erase_sector(uint32_t sector)
-{
- wait_write_complete();
- enable_write();
- uint32_t address = (sector * SECTOR_SIZE);
- select_device();
- uint8_t tx[4] = {OPCODE_SECTOR_ERASE, ((address >> 16) & 0xFF), ((address >> 8) & 0xFF), (address & 0xFF)};
- write_buffer(tx, 4);
- release_device();
-}
-void SST25::erase_block_32K(uint32_t start_sector)
-{
- wait_write_complete();
- enable_write();
- uint32_t address = (start_sector * SECTOR_SIZE);
- select_device();
- uint8_t tx[4] = {OPCODE_BLOCK_ERASE_32K, ((address >> 16) & 0xFF), ((address >> 8) & 0xFF), (address & 0xFF)};
- write_buffer(tx, 4);
- release_device();
-}
-void SST25::erase_block_64K(uint32_t start_sector)
-{
- wait_write_complete();
- enable_write();
- uint32_t address = (start_sector * SECTOR_SIZE);
- select_device();
- uint8_t tx[4] = {OPCODE_BLOCK_ERASE_64K, ((address >> 16) & 0xFF), ((address >> 8) & 0xFF), (address & 0xFF)};
- write_buffer(tx, 4);
- release_device();
-}
-void SST25::erase_full_chip()
-{
- wait_write_complete();
- enable_write();
- select_device();
- _spi->send(OPCODE_CHIP_ERASE);
- release_device();
-}
-uint8_t SST25::read_status_register()
-{
- select_device();
- uint8_t tx[1] = {OPCODE_RDSR};
- write_buffer(tx, 1);
- uint8_t rx[1];
- read_buffer(rx, 1);
- release_device();
- return (rx[0]);
-}
-void SST25::enable_write()
-{
- wait_write_complete();
- select_device();
- _spi->send(OPCODE_WREN);
- release_device();
-}
-void SST25::disable_write()
-{
- wait_write_complete();
- select_device();
- _spi->send(OPCODE_WRDI);
- release_device();
-}
-void SST25::enable_write_status_register()
-{
- //wait_write_complete();
- select_device();
- _spi->send(OPCODE_EWSR);
- release_device();
-}
-void SST25::write_status_register(uint8_t data)
-{
- //wait_write_complete();
- select_device();
- uint8_t tx[2] = {OPCODE_WRSR, data};
- write_buffer(tx, 2);
- release_device();
-}
-uint16_t SST25::read_id()
-{
- select_device();
- uint8_t tx[4] = {OPCODE_RDID_ALT, 0, 0, 0};
- write_buffer(tx, 4);
- uint8_t rx[2];
- read_buffer(rx, 2);
- release_device();
- return ((rx[0] << 8) | rx[1]);
-}
-uint32_t SST25::read_jedec_id()
-{
- select_device();
- uint8_t tx[1] = {OPCODE_JEDEC_ID};
- write_buffer(tx, 1);
- uint8_t rx[3];
- read_buffer(rx, 3);
- release_device();
- return ((rx[0] << 16) | (rx[1] << 8) | rx[3]);
-}
-
-void SST25::select_device()
-{
- _nss->clear();
- while(_spi->get_flag_status(Flag::BUSY_FLAG));
-}
-void SST25::release_device()
-{
- _nss->set();
-}
-void SST25::write_buffer(const uint8_t *buf, int len)
-{
- while(len--)
- _spi->send(*buf++);
-}
-void SST25::read_buffer(uint8_t *buf, int len)
-{
- uint8_t res = _spi->read();
- while(len--)
- *buf++ = _spi->read();
-}
-void SST25::wait_write_complete()
-{
- uint8_t status = read_status_register();
- while (status & SST25_SR_BUSY) {
- status = read_status_register();
- }
-}
diff --git a/emb/pastilda/flash/flash_memory.cpp b/emb/pastilda/flash/flash_memory.cpp
deleted file mode 100644
index 2afa1d8..0000000
--- a/emb/pastilda/flash/flash_memory.cpp
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * This file is part of the pastilda project.
- * hosted at http://github.com/thirdpin/pastilda
- *
- * Copyright (C) 2016 Third Pin LLC
- * Written by Anastasiia Lazareva <a.lazareva@thirdpin.ru>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "flash_memory.h"
-
-FlashMemory *flash_pointer;
-
-FlashMemory::FlashMemory()
-{
- flash_pointer = this;
-
- SPI_CPP_Extension::SPI_Conf sst25_conf = { 1, PA7, PA6, PA5 };
- _spi = new SPI_ext(sst25_conf);
-
- _spi->reset();
- _spi->disable();
- _spi->set_master_mode();
- _spi->set_baudrate_prescaler(BAUDRATE_FPCLK_DIV_2);
- _spi->set_standard_mode(MODE_0);
- _spi->set_data_drame_format(DFF_8BIT);
- _spi->set_bit_position(MSB_FIRST);
- _spi->enable_ss_output();
- _spi->set_software_slave_management(State::ENABLE);
- _spi->set_nss(HIGH);
- _spi->enable();
-
- _sst25 = new SST25(_spi, PA4);
- _sst25->disable_wtite_protection();
-
- FatState state = _get_fat_state();
- if (state == FatState::FAT_ERROR) {
- _set_fat_system_region();
- }
-}
-
-uint16_t FlashMemory::get_sector_size(const struct block_device *dev)
-{
- (void)dev;
- return (FAKE_SECTOR_SIZE);
-}
-
-int FlashMemory::read_sectors(const struct block_device *dev, uint32_t sector, uint32_t count, void *buf)
-{
- (void)dev;
- uint32_t end_sector = sector + count - 1;
- if (end_sector >= FAKE_SECTOR_COUNT) {
- return (0);
- }
-
- uint32_t real_start_sector = sector / 8;
- uint32_t real_end_sector = end_sector / 8;
- uint32_t real_sector_count = real_end_sector - real_start_sector + 1;
- uint32_t real_start_sector_part = (sector % 8);
-
- uint32_t data_size = real_sector_count * SECTOR_SIZE;
- uint8_t data[data_size];
-
- flash_pointer->_sst25->read_sectors(real_start_sector, real_sector_count, data);
-
- uint32_t start_address = real_start_sector_part * FAKE_SECTOR_SIZE;
- uint32_t end_address = start_address + (count * FAKE_SECTOR_SIZE);
-
- for (int i = start_address, j = 0; i < end_address; i++, j++) {
- ((uint8_t*)buf)[j] = data[i];
- }
-
- return (count);
-}
-
-int FlashMemory::write_sectors(const struct block_device *dev, uint32_t sector, uint32_t count, const void *buf)
-{
- (void)dev;
- uint32_t end_sector = (sector + count - 1);
- if (end_sector >= FAKE_SECTOR_COUNT) {
- return (0);
- }
-
- uint32_t real_start_sector = sector / 8;
- uint32_t real_end_sector = end_sector / 8;
- uint32_t real_sector_count = real_end_sector - real_start_sector + 1;
- uint32_t real_start_sector_part = (sector % 8);
-
- uint32_t copy_size = real_sector_count * SECTOR_SIZE;
- uint8_t sector_copy[copy_size];
-
- flash_pointer->_sst25->read_sectors(real_start_sector, real_sector_count, sector_copy);
-
- uint32_t start_address = real_start_sector_part * FAKE_SECTOR_SIZE;
- uint32_t end_address = start_address + (count * FAKE_SECTOR_SIZE);
-
- for (int i = start_address, j = 0; i < end_address; i++, j++) {
- sector_copy[i] = ((uint8_t*)buf)[j];
- }
-
- flash_pointer->_sst25->write_sectors(real_start_sector, real_sector_count, sector_copy);
- return (count);
-}
-
-int FlashMemory::flash_read(uint32_t lba, uint8_t *copy_to)
-{
- memset(copy_to, 0, FAKE_SECTOR_SIZE);
- if (lba >= FAKE_SECTOR_COUNT) {
- return (1);
- }
- else {
- read_sectors(0, lba, 1, copy_to);
- return (0);
- }
-}
-
-void FlashMemory::erase_chip()
-{
- _sst25->erase_full_chip();
-}
-int FlashMemory::flash_write(uint32_t lba, const uint8_t *copy_from)
-{
- if (lba >= FAKE_SECTOR_COUNT) {
- return (1);
- }
- else {
- write_sectors(0, lba, 1, copy_from);
- return (0);
- }
-}
-int FlashMemory::flash_blocks(void)
-{
- return (FAKE_SECTOR_COUNT);
-}
-FatState FlashMemory::_get_fat_state()
-{
- uint8_t buf[2];
- _sst25->read(510, 2, buf);
- uint16_t signature = ((buf[0] << 8) | buf[1]);
- if (signature == BOOT_SIGNATURE) {
- return (FatState::FAT_READY);
- }
-
- return (FatState::FAT_ERROR);
-}
-void FlashMemory::_set_fat_system_region()
-{
- _sst25->erase_full_chip();
- _set_boot_region();
- _set_fat_region();
- _set_root_dir_region();
-}
-
-void FlashMemory::_set_boot_region()
-{
- uint8_t copy_to[BOOT_SIZE];
- memset(copy_to, 0, BOOT_SIZE);
-
- uint8_t BootSector[] = {
- 0xEB, 0x58, 0x90, // code to jump to the bootstrap code
- 0x57, 0x49, 0x4E, 0x49, 0x4D, 0x41, 0x47, 0x45, // OEM ID
- 0x00, 0x02, // bytes per sector
- 0x08, // sectors per cluster (0x04)
- 0x01, 0x00, // # of reserved sectors (1 boot sector)
- 0x02, // FAT copies (2)
- 0x00, 0x02, // root entries (512)
- 0x00, 0x40, // total number of sectors
- 0xF8, // media descriptor (0xF8 = Fixed disk)
- 0x08, 0x00, // sectors per FAT (16)
- 0x00, 0x00, // sectors per track (0)
- 0x00, 0x00, // number of heads (0)
- 0x00, 0x00, 0x00, 0x00, // hidden sectors (0)
- 0x00, 0x00, 0x00, 0x00, // large number of sectors (0)
- 0x80, // drive number (0)
- 0x00, // reserved
- 0x29, // extended boot signature
- 0x10, 0x5C, 0xD1, 0x34, // volume serial number
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, // volume label
- 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20 // filesystem type
- };
-
- memcpy(copy_to, BootSector, sizeof(BootSector));
- copy_to[BOOT_SIZE - 2] = 0x55;
- copy_to[BOOT_SIZE - 1] = 0xAA;
-
- write_sectors(0, BOOT_SECTOR, BOOT_SECTOR_COUNT, copy_to);
-}
-void FlashMemory::_set_fat_region()
-{
- uint8_t copy_to[FAT_SIZE];
-
- memset(copy_to, 0, FAT_SIZE);
- copy_to[0] = 0xF8;
- copy_to[1] = 0xFF;
- copy_to[2] = 0xFF;
- copy_to[3] = 0xFF;
-
- write_sectors(0, FAT1_SECTOR, FAT_SECTOR_COUNT, copy_to);
- write_sectors(0, FAT2_SECTOR, FAT_SECTOR_COUNT, copy_to);
-}
-void FlashMemory::_set_root_dir_region()
-{
- uint8_t copy_to[ROOT_SIZE];
- memset(copy_to, 0, ROOT_SIZE);
- write_sectors(0, 17, ROOT_SECTOR_COUNT, copy_to);
-}
diff --git a/emb/pastilda/flash/flash_memory.h b/emb/pastilda/flash/flash_memory.h
deleted file mode 100644
index 681ae22..0000000
--- a/emb/pastilda/flash/flash_memory.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * This file is part of the pastilda project.
- * hosted at http://github.com/thirdpin/pastilda
- *
- * Copyright (C) 2016 Third Pin LLC
- * Written by Anastasiia Lazareva <a.lazareva@thirdpin.ru>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef FLASH_MEMORY_H
-#define FLASH_MEMORY_H
-
-#include <string.h>
-
-extern "C"
-{
-#include "blockdev.h"
-#include "openfat.h"
-#include "mbr.h"
-}
-
-#include "spi_ext.h"
-#include "SST25.h"
-
-using namespace SPI_CPP_Extension;
-
-#define WBVAL(x) ((x) & 0xFF), (((x) >> 8) & 0xFF)
-#define QBVAL(x) ((x) & 0xFF), (((x) >> 8) & 0xFF), (((x) >> 16) & 0xFF), (((x) >> 24) & 0xFF)
-
-constexpr uint16_t FAKE_SECTOR_SIZE = 512;
-constexpr uint16_t FAKE_SECTOR_COUNT = 16384; //(MEMORY_SIZE / FAKE_SECTOR_SIZE);
-constexpr uint16_t BOOT_SIGNATURE = 0x55AA;
-
-constexpr uint16_t BYTES_PER_SECTOR = 512;
-constexpr uint16_t SECTORS_PER_CLUSTER = 4;
-constexpr uint16_t RESERVED_SECTORS = 1;
-constexpr uint16_t FAT_COPIES = 2;
-constexpr uint16_t ROOT_ENTRIES = 512;
-
-constexpr uint16_t BOOT_SIZE = 512;
-constexpr uint16_t BOOT_SECTOR = 0;
-constexpr uint16_t BOOT_SECTOR_COUNT = 1;
-
-constexpr uint16_t FAT_SIZE = 4096;
-constexpr uint16_t FAT_SECTOR_COUNT = 8;
-constexpr uint16_t FAT1_SECTOR = 1;
-constexpr uint16_t FAT2_SECTOR = 1 + FAT_SECTOR_COUNT;
-
-constexpr uint16_t ROOT_SIZE = 16384;
-constexpr uint16_t ROOT_SECTOR_COUNT = 32;
-
-typedef enum {
- FAT_READY,
- FAT_ERROR
-}FatState;
-
-class FlashMemory
-{
-public:
- FlashMemory();
- static uint16_t get_sector_size(const struct block_device *dev);
- static int read_sectors(const struct block_device *dev, uint32_t sector, uint32_t count, void *buf);
- static int write_sectors(const struct block_device *dev, uint32_t sector, uint32_t count, const void *buf);
-
- void erase_chip();
-
- static int flash_read(uint32_t lba, uint8_t *copy_to);
- static int flash_write(uint32_t lba, const uint8_t *copy_from);
- static int flash_blocks(void);
-
- void print_tree();
-
-private:
- SST25 *_sst25;
- SPI_ext *_spi;
-
- struct block_device dev;
- struct block_mbr_partition part;
- struct fat_vol_handle vol;
- struct fat_file_handle dir;
- struct fat_file_handle file;
-
- FatState _get_fat_state();
- void _set_fat_system_region();
- void _set_boot_region();
- void _set_fat_region();
- void _set_root_dir_region();
-};
-
-#endif
diff --git a/emb/pastilda/fs/drv/SST25.cpp b/emb/pastilda/fs/drv/SST25.cpp
new file mode 100644
index 0000000..314a688
--- /dev/null
+++ b/emb/pastilda/fs/drv/SST25.cpp
@@ -0,0 +1,368 @@
+/*
+ * This file is part of the pastilda project.
+ * hosted at http://github.com/thirdpin/pastilda
+ *
+ * Copyright (C) 2016 Third Pin LLC
+ *
+ * Written by:
+ * Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ * Dmitrii Lisin <mrlisdim@ya.ru>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <fs/drv/SST25.h>
+#include "stdio.h"
+
+static volatile bool data_received = false;
+static volatile bool data_transmitted = false;
+
+SST25::SST25()
+: _spi(SPI_CONF), _cs(SPI_CS)
+{
+ _spi_config();
+ _dma_config();
+ _cs_config();
+}
+
+void SST25::disable_write_protection()
+{
+ enable_write_status_register();
+ write_status_register(DISABLE_WRITE_PROTECTION);
+}
+
+void SST25::read(uint32_t address, uint32_t count, uint8_t* buf)
+{
+ _wait_write_complete();
+ _select_device();
+ _send_command(OPCODE_READ, address);
+ _read_data(buf, count);
+ _release_device();
+}
+
+void SST25::read_high_speed(uint32_t address, uint32_t count, uint8_t* buf)
+{
+ _wait_write_complete();
+ _select_device();
+ _send_command(OPCODE_FAST_READ, address, true);
+ _read_data(buf, count);
+ _release_device();
+}
+
+void SST25::page_program(uint32_t address, uint8_t *data, uint16_t count)
+{
+ _wait_write_complete();
+ enable_write();
+ _select_device();
+ _send_command(OPCODE_PAGE_PROGRAM, address);
+ _write_data(data, count);
+ _release_device();
+}
+
+void SST25::erase_sector(uint32_t sector)
+{
+ uint32_t address = (sector * SECTOR_SIZE);
+
+ _wait_write_complete();
+ enable_write();
+ _select_device();
+ _send_command(OPCODE_SECTOR_ERASE, address);
+ _release_device();
+}
+
+void SST25::erase_block_32K(uint32_t start_sector)
+{
+ uint32_t address = (start_sector * SECTOR_SIZE);
+
+ _wait_write_complete();
+ enable_write();
+ _select_device();
+ _send_command(OPCODE_BLOCK_ERASE_32K, address);
+ _release_device();
+}
+
+void SST25::erase_block_64K(uint32_t start_sector)
+{
+ uint32_t address = (start_sector * SECTOR_SIZE);
+
+ _wait_write_complete();
+ enable_write();
+ _select_device();
+ _send_command(OPCODE_BLOCK_ERASE_64K, address);
+ _release_device();
+}
+
+void SST25::erase_full_chip()
+{
+ _wait_write_complete();
+ enable_write();
+ _select_device();
+ _send_command(OPCODE_CHIP_ERASE);
+ _release_device();
+}
+
+uint8_t SST25::read_status_register()
+{
+ _select_device();
+ _send_command(OPCODE_RDSR);
+ uint8_t result;
+ _read_data(&result, sizeof(uint8_t));
+ _release_device();
+ return (result);
+}
+
+void SST25::enable_write()
+{
+ _wait_write_complete();
+ _select_device();
+ _send_command(OPCODE_WREN);
+ _release_device();
+}
+
+void SST25::disable_write()
+{
+ _wait_write_complete();
+ _select_device();
+ _send_command(OPCODE_WRDI);
+ _release_device();
+}
+
+void SST25::enable_write_status_register()
+{
+ _select_device();
+ _send_command(OPCODE_EWSR);
+ _release_device();
+}
+
+void SST25::write_status_register(uint8_t data)
+{
+ _select_device();
+ _send_command(OPCODE_WRSR);
+ _write_data(&data, sizeof(uint8_t));
+ _release_device();
+}
+
+uint16_t SST25::read_id()
+{
+ _select_device();
+ _send_command(OPCODE_RDID_ALT, 0);
+ uint16_t result = 0;
+ _read_data((uint8_t*)&result, sizeof(uint16_t));
+ _release_device();
+ return (result);
+}
+
+uint32_t SST25::read_jedec_id()
+{
+ _select_device();
+ _send_command(OPCODE_JEDEC_ID);
+ uint32_t result;
+ _read_data((uint8_t*)&result, 3);
+ _release_device();
+ return (result);
+}
+
+int SST25::read_sector(uint32_t sector, void *buf)
+{
+ if(sector >= (SECTOR_COUNT)) {
+ return (0);
+ }
+
+ uint32_t address = (sector * SECTOR_SIZE);
+ read_high_speed(address, FAKE_SECTOR_SIZE, (uint8_t*)buf);
+
+ return (1);
+}
+
+int SST25::write_sector(uint32_t sector, const void *buf)
+{
+ if(sector >= (SECTOR_COUNT)) {
+ return (0);
+ }
+
+ erase_sector(sector);
+ uint32_t address = (sector * SECTOR_SIZE);
+
+ for (int j = 0; j < PAGE_COUNT_IN_FAKE_SECTOR; j++) {
+ page_program(address, (uint8_t*)buf, PAGE_SIZE);
+ address += PAGE_SIZE;
+ buf += PAGE_SIZE;
+ }
+
+ return (1);
+}
+
+void SST25::_spi_config()
+{
+ _spi.reset();
+ _spi.disable();
+ _spi.set_master_mode();
+ _spi.set_baudrate_prescaler(BAUDRATE_FPCLK_DIV_2);
+ _spi.set_standard_mode(MODE_0);
+ _spi.set_data_drame_format(DFF_8BIT);
+ _spi.set_bit_position(MSB_FIRST);
+ _spi.enable_ss_output();
+ _spi.set_software_slave_management(State::ENABLE);
+ _spi.set_nss(HIGH);
+ _spi.enable();
+}
+
+void SST25::_dma_config()
+{
+ rcc_periph_reset_pulse(rcc_periph_rst::RST_DMA2);
+
+ dma_stream_reset(SPI_DMA, SPI_DMA_RX_STREAM);
+ dma_set_peripheral_address(SPI_DMA, SPI_DMA_RX_STREAM, (uint32_t)&SPI_DR(SPI));
+ dma_set_peripheral_size(SPI_DMA, SPI_DMA_RX_STREAM, DMA_SxCR_PSIZE_8BIT);
+ dma_set_memory_size(SPI_DMA, SPI_DMA_RX_STREAM, DMA_SxCR_MSIZE_8BIT);
+ dma_disable_peripheral_increment_mode(SPI_DMA, SPI_DMA_RX_STREAM);
+ dma_set_transfer_mode(SPI_DMA, SPI_DMA_RX_STREAM, DMA_SxCR_DIR_PERIPHERAL_TO_MEM);
+ dma_set_priority(SPI_DMA, SPI_DMA_RX_STREAM, DMA_SxCR_PL_HIGH);
+ dma_channel_select(SPI_DMA, SPI_DMA_RX_STREAM, SPI_DMA_CHANNEL);
+ dma_enable_transfer_complete_interrupt(SPI_DMA, SPI_DMA_RX_STREAM);
+ nvic_set_priority(SPI_DMA_RX_NVIC, 0);
+ nvic_enable_irq(SPI_DMA_RX_NVIC);
+
+ dma_stream_reset(SPI_DMA, SPI_DMA_TX_STREAM);
+ dma_set_peripheral_address(SPI_DMA, SPI_DMA_TX_STREAM, (uint32_t)&SPI_DR(SPI));
+ dma_set_peripheral_size(SPI_DMA, SPI_DMA_TX_STREAM, DMA_SxCR_PSIZE_8BIT);
+ dma_set_memory_size(SPI_DMA, SPI_DMA_TX_STREAM, DMA_SxCR_MSIZE_8BIT);
+ dma_disable_peripheral_increment_mode(SPI_DMA, SPI_DMA_TX_STREAM);
+ dma_set_transfer_mode(SPI_DMA, SPI_DMA_TX_STREAM, DMA_SxCR_DIR_MEM_TO_PERIPHERAL);
+ dma_set_priority(SPI_DMA, SPI_DMA_TX_STREAM, DMA_SxCR_PL_HIGH);
+ dma_channel_select(SPI_DMA, SPI_DMA_TX_STREAM, SPI_DMA_CHANNEL);
+ dma_enable_transfer_complete_interrupt(SPI_DMA, SPI_DMA_TX_STREAM);
+ nvic_set_priority(SPI_DMA_TX_NVIC, 0);
+ nvic_enable_irq(SPI_DMA_TX_NVIC);
+}
+
+void SST25::_cs_config()
+{
+ _cs.mode_setup(GPIO_CPP_Extension::Mode::OUTPUT, GPIO_CPP_Extension::PullMode::NO_PULL);
+ _cs.set_output_options(GPIO_CPP_Extension::OutputType::PUSH_PULL, GPIO_CPP_Extension::Speed::FAST_50MHz);
+ _cs.set();
+}
+
+void SST25::_select_device()
+{
+ _cs.clear();
+ while(_spi.get_flag_status(Flag::BUSY_FLAG));
+}
+
+void SST25::_release_device()
+{
+ _cs.set();
+}
+
+void SST25::_wait_write_complete()
+{
+ while (read_status_register() & SST25_SR_BUSY);
+}
+
+void SST25::_send_command(uint8_t command, int32_t address, bool dummy)
+{
+ uint8_t cmd[COMMAND_SIZE];
+ uint32_t length;
+
+ cmd[0] = command;
+ length = 1;
+
+ if (address >= 0) {
+ cmd[1] = (uint8_t)((address >> 0x10) & 0xFF);
+ cmd[2] = (uint8_t)((address >> 0x08) & 0xFF);
+ cmd[3] = (uint8_t)((address >> 0x00) & 0xFF);
+ length = 4;
+ }
+
+ if (dummy) {
+ cmd[4] = DUMMY_BYTE;
+ length = 5;
+ }
+
+ _transfer_data(false, cmd, length);
+}
+
+void SST25::_transfer_data(bool receive, uint8_t *buf, uint16_t len)
+{
+ uint16_t rw_workbyte = 0xffff;
+
+ if (len <= COMMAND_SIZE) {
+ if (receive) {
+ while(len--) {
+ *buf++ = _spi.read(0x00);
+ }
+ }
+
+ else {
+ while(len--) {
+ _spi.write(*buf++);
+ }
+ _spi.write_end();
+ }
+ }
+
+ else {
+ if (receive) {
+ dma_set_memory_address(SPI_DMA, SPI_DMA_RX_STREAM, (uint32_t)buf);
+ dma_set_number_of_data(SPI_DMA, SPI_DMA_RX_STREAM, len);
+ dma_enable_memory_increment_mode(SPI_DMA,SPI_DMA_RX_STREAM);
+
+ dma_set_memory_address(SPI_DMA, SPI_DMA_TX_STREAM, (uint32_t)&rw_workbyte);
+ dma_set_number_of_data(SPI_DMA, SPI_DMA_TX_STREAM, len);
+ dma_disable_memory_increment_mode(SPI_DMA,SPI_DMA_TX_STREAM);
+ }
+
+ else {
+ dma_set_memory_address(SPI_DMA, SPI_DMA_RX_STREAM, (uint32_t)&rw_workbyte);
+ dma_set_number_of_data(SPI_DMA, SPI_DMA_RX_STREAM, len);
+ dma_disable_memory_increment_mode(SPI_DMA,SPI_DMA_RX_STREAM);
+
+ dma_set_memory_address(SPI_DMA, SPI_DMA_TX_STREAM, (uint32_t)buf);
+ dma_set_number_of_data(SPI_DMA, SPI_DMA_TX_STREAM, len);
+ dma_enable_memory_increment_mode(SPI_DMA,SPI_DMA_TX_STREAM);
+ }
+
+ dma_enable_stream(SPI_DMA, SPI_DMA_RX_STREAM);
+ dma_enable_stream(SPI_DMA, SPI_DMA_TX_STREAM);
+
+ _spi.enable_rx_dma();
+ _spi.enable_tx_dma();
+
+ while (!data_received && !data_transmitted);
+ data_received = false;
+ data_transmitted = false;
+
+ dma_disable_stream(SPI_DMA, SPI_DMA_RX_STREAM);
+ dma_disable_stream(SPI_DMA, SPI_DMA_TX_STREAM);
+
+ _spi.disable_rx_dma();
+ _spi.disable_tx_dma();
+ }
+}
+
+void SPI_DMA_RX_IRQ(void)
+{
+ if (dma_get_interrupt_flag(SPI_DMA, SPI_DMA_RX_STREAM, DMA_TCIF)) {
+ dma_clear_interrupt_flags(SPI_DMA, SPI_DMA_RX_STREAM, DMA_TCIF);
+ data_received = true;
+ }
+}
+
+void SPI_DMA_TX_IRQ(void)
+{
+ if (dma_get_interrupt_flag(SPI_DMA, SPI_DMA_TX_STREAM, DMA_TCIF)) {
+ dma_clear_interrupt_flags(SPI_DMA, SPI_DMA_TX_STREAM, DMA_TCIF);
+ data_transmitted = true;
+ }
+}
diff --git a/emb/pastilda/flash/drv/SST25.h b/emb/pastilda/fs/drv/SST25.h
index 3b38fb4..a265d58 100644
--- a/emb/pastilda/flash/drv/SST25.h
+++ b/emb/pastilda/fs/drv/SST25.h
@@ -3,7 +3,10 @@
* hosted at http://github.com/thirdpin/pastilda
*
* Copyright (C) 2016 Third Pin LLC
- * Written by Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ *
+ * Written by:
+ * Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ * Dmitrii Lisin <mrlisdim@ya.ru>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,6 +27,9 @@
#include <string.h>
+#include <libopencm3/cm3/nvic.h>
+#include <libopencm3/stm32/rcc.h>
+#include <libopencm3/stm32/dma.h>
#include "spi_ext.h"
#include "gpio_ext.h"
@@ -53,17 +59,17 @@ constexpr uint8_t OPCODE_READ_SID = 0x88;
constexpr uint8_t OPCODE_PROGRAM_SID = 0xA5;
constexpr uint8_t OPCODE_LOCKOUT_SID = 0x85;
-constexpr uint8_t SST25_MANUFACTURER = 0xBF; /* SST manufacturer ID */
-constexpr uint8_t SST25_DEVICE_ID = 0x4B; /* SSTVF032B device ID */
+constexpr uint8_t SST25_MANUFACTURER = 0xBF;
+constexpr uint8_t SST25_DEVICE_ID = 0x4B;
-constexpr uint8_t SST25_JEDEC_MANUFACTURER = 0xBF; /* SST manufacturer ID */
-constexpr uint8_t SST25_JEDEC_MEMORY_TYPE = 0x25; /* SST25 memory type */
-constexpr uint8_t SST25_JEDEC_MEMORY_CAPACITY = 0x4B; /* SST25VF032B memory capacity */
+constexpr uint8_t SST25_JEDEC_MANUFACTURER = 0xBF;
+constexpr uint8_t SST25_JEDEC_MEMORY_TYPE = 0x25;
+constexpr uint8_t SST25_JEDEC_MEMORY_CAPACITY = 0x4B;
-constexpr uint8_t SST25_SR_BUSY = (0x1 << 0); /* Bit 0: Write in progress */
-constexpr uint8_t SST25_SR_WEL = (0x1 << 1); /* Bit 1: Write enable latch bit */
+constexpr uint8_t SST25_SR_BUSY = (0x1 << 0); /* Bit 0: Write in progress */
+constexpr uint8_t SST25_SR_WEL = (0x1 << 1); /* Bit 1: Write enable latch bit */
constexpr uint8_t SST25_SR_BP_MASK = (0xF << 2);
-constexpr uint8_t SST25_SR_BP_NONE = (0x0 << 2);/* Unprotected */
+constexpr uint8_t SST25_SR_BP_NONE = (0x0 << 2); /* Unprotected */
constexpr uint8_t SST25_SR_BP_UPPER128 = (0x1 << 2); /* Upper 64th */
constexpr uint8_t SST25_SR_BP_UPPER64 = (0x2 << 2); /* Upper 32nd */
constexpr uint8_t SST25_SR_BP_UPPER32 = (0x3 << 2); /* Upper 16th */
@@ -80,20 +86,38 @@ constexpr uint8_t DUMMY_BYTE = 0xFE;
constexpr uint16_t DISABLE_WRITE_PROTECTION = 0x00;
constexpr uint16_t SECTOR_SIZE = 4096;
+constexpr uint16_t FAKE_SECTOR_SIZE = 512;
constexpr uint32_t MEMORY_SIZE = 0x800000;
constexpr uint16_t SECTOR_COUNT = MEMORY_SIZE / SECTOR_SIZE;
constexpr uint16_t PAGE_SIZE = 256;
constexpr uint16_t PAGE_COUNT_IN_SECTOR = 16;
+constexpr uint16_t PAGE_COUNT_IN_FAKE_SECTOR = 2;
+constexpr uint16_t COMMAND_SIZE = 5;
+
+constexpr Pinout SPI_CS = PA4;
+constexpr uint32_t SPI = SPI1;
+constexpr SPI_Conf SPI_CONF = {1, PA7, PA6, PA5};
+constexpr uint32_t SPI_DMA = DMA2;
+constexpr uint32_t SPI_DMA_RX_STREAM = DMA_STREAM0;
+constexpr uint32_t SPI_DMA_TX_STREAM = DMA_STREAM3;
+constexpr uint32_t SPI_DMA_CHANNEL = DMA_SxCR_CHSEL_3;
+constexpr uint32_t SPI_DMA_RX_NVIC = NVIC_DMA2_STREAM0_IRQ;
+constexpr uint32_t SPI_DMA_TX_NVIC = NVIC_DMA2_STREAM3_IRQ;
+
+#define SPI_DMA_RX_IRQ dma2_stream0_isr
+#define SPI_DMA_TX_IRQ dma2_stream3_isr
+
+extern "C" void SPI_DMA_RX_IRQ();
+extern "C" void SPI_DMA_TX_IRQ();
class SST25
{
public:
- SST25(SPI_ext *spi, Pinout nss_pin);
- int read_sectors(uint32_t sector, uint32_t count, void *buf);
- int write_sectors(uint32_t sector, uint32_t count, const void *buf);
- void disable_wtite_protection();
+ SPI_ext _spi;
+ SST25();
+ void disable_write_protection();
void read(uint32_t address, uint32_t count, uint8_t* buf);
void read_high_speed(uint32_t address, uint32_t count, uint8_t* buf);
void page_program(uint32_t address, uint8_t *data, uint16_t count);
@@ -111,15 +135,31 @@ public:
uint16_t read_id();
uint32_t read_jedec_id();
+ int read_sector(uint32_t sector, void *buf);
+ int write_sector(uint32_t sector, const void *buf);
+
private:
- SPI_ext *_spi;
- GPIO_ext *_nss;
-
- void select_device();
- void release_device();
- void write_buffer(const uint8_t *buf, int len);
- void read_buffer(uint8_t *buf, int len);
- void wait_write_complete();
+
+ GPIO_ext _cs;
+
+ void _spi_config();
+ void _dma_config();
+ void _cs_config();
+ void _select_device();
+ void _release_device();
+ void _send_command(uint8_t command, int32_t address = -1, bool dummy = false);
+ void _wait_write_complete();
+ void _transfer_data(bool receive, uint8_t *buf, uint16_t len);
+
+ void _read_data(uint8_t *buf, int len)
+ {
+ _transfer_data(true, buf, len);
+ }
+
+ void _write_data(uint8_t *buf, int len)
+ {
+ _transfer_data(false, buf, len);
+ }
};
#endif
diff --git a/emb/pastilda/fs/fatfs/diskio.cpp b/emb/pastilda/fs/fatfs/diskio.cpp
new file mode 100644
index 0000000..0c34465
--- /dev/null
+++ b/emb/pastilda/fs/fatfs/diskio.cpp
@@ -0,0 +1,101 @@
+/*-----------------------------------------------------------------------*/
+/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2014 */
+/*-----------------------------------------------------------------------*/
+/* If a working storage control module is available, it should be */
+/* attached to the FatFs via a glue function rather than modifying it. */
+/* This is an example of glue functions to attach various exsisting */
+/* storage control modules to the FatFs module with a defined API. */
+/*-----------------------------------------------------------------------*/
+
+#include <fs/fatfs/diskio.h> /* FatFs lower layer API */
+
+void disk_set_callbacks(int (*access)(MemoryCommand cmd, uint32_t sector, uint32_t count, uint8_t *copy_to, const uint8_t *copy_from))
+{
+ access_memory = access;
+}
+
+DSTATUS disk_status (BYTE pdrv)
+{
+ return (0);
+}
+
+/*-----------------------------------------------------------------------*/
+/* Initialize a Drive */
+/*-----------------------------------------------------------------------*/
+
+DSTATUS disk_initialize (BYTE pdrv)
+{
+ if (pdrv != 0) {
+ return (STA_NOINIT);
+ }
+
+ return (0);
+}
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Read Sector(s) */
+/*-----------------------------------------------------------------------*/
+
+DRESULT disk_read (
+ BYTE pdrv, /* Physical drive nmuber (0..) */
+ BYTE *buff, /* Data buffer to store read data */
+ DWORD sector, /* Sector address (LBA) */
+ UINT count /* Number of sectors to read (1..128) */
+)
+{
+ if (pdrv != 0)
+ {
+ return (RES_PARERR);
+ }
+
+ access_memory(READ, sector, count, buff, 0);
+ return (RES_OK);
+}
+
+#if _USE_WRITE
+DRESULT disk_write (
+ BYTE pdrv, /* Physical drive nmuber (0..) */
+ const BYTE *buff, /* Data to be written */
+ DWORD sector, /* Sector address (LBA) */
+ UINT count /* Number of sectors to write (1..128) */
+)
+{
+ if (pdrv != 0)
+ {
+ return (RES_PARERR);
+ }
+
+ access_memory(WRITE, sector, count, 0, buff);
+ return (RES_OK);
+}
+#endif
+
+/*-----------------------------------------------------------------------*/
+/* Miscellaneous Functions */
+/*-----------------------------------------------------------------------*/
+
+#if _USE_IOCTL
+DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void *buff) {
+ if (pdrv != 0)
+ return (RES_PARERR);
+
+ switch (cmd)
+ {
+ case CTRL_SYNC:
+ //do nothing. By calling SD_WaitReadOperation and
+ //SD_WaitWriteOperation we already ensure that operations
+ //complete in the read and write functions.
+ return (RES_OK);
+ break;
+ default:
+ return (RES_PARERR);
+ }
+}
+#endif
+
+DWORD get_fattime (void) {
+ return (get_counter_ms());
+}
+
diff --git a/emb/pastilda/fs/fatfs/diskio.h b/emb/pastilda/fs/fatfs/diskio.h
new file mode 100644
index 0000000..877605f
--- /dev/null
+++ b/emb/pastilda/fs/fatfs/diskio.h
@@ -0,0 +1,77 @@
+/*-----------------------------------------------------------------------/
+/ Low level disk interface modlue include file (C)ChaN, 2014 /
+/-----------------------------------------------------------------------*/
+
+#ifndef _DISKIO_DEFINED
+#define _DISKIO_DEFINED
+
+
+#define _USE_WRITE 1 /* 1: Enable disk_write function */
+#define _USE_IOCTL 1 /* 1: Enable disk_ioctl fucntion */
+
+#include <fs/fatfs/integer.h>
+#include "systick_ext.h"
+#include <fs/file_system_defines.h>
+
+/* Status of Disk Functions */
+typedef BYTE DSTATUS;
+
+/* Results of Disk Functions */
+typedef enum {
+ RES_OK = 0, /* 0: Successful */
+ RES_ERROR, /* 1: R/W Error */
+ RES_WRPRT, /* 2: Write Protected */
+ RES_NOTRDY, /* 3: Not Ready */
+ RES_PARERR /* 4: Invalid Parameter */
+} DRESULT;
+
+
+/*---------------------------------------*/
+/* Prototypes for disk control functions */
+
+void disk_set_callbacks(int (*access)(MemoryCommand cmd, uint32_t sector, uint32_t count, uint8_t *copy_to, const uint8_t *copy_from));
+static int (*access_memory)(MemoryCommand cmd, uint32_t sector, uint32_t count, uint8_t *copy_to, const uint8_t *copy_from);
+
+DSTATUS disk_initialize (BYTE pdrv);
+DSTATUS disk_status (BYTE pdrv);
+DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count);
+DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count);
+DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
+
+
+/* Disk Status Bits (DSTATUS) */
+
+#define STA_NOINIT 0x01 /* Drive not initialized */
+#define STA_NODISK 0x02 /* No medium in the drive */
+#define STA_PROTECT 0x04 /* Write protected */
+
+
+/* Command code for disk_ioctrl fucntion */
+
+/* Generic command (Used by FatFs) */
+#define CTRL_SYNC 0 /* Complete pending write process (needed at _FS_READONLY == 0) */
+#define GET_SECTOR_COUNT 1 /* Get media size (needed at _USE_MKFS == 1) */
+#define GET_SECTOR_SIZE 2 /* Get sector size (needed at _MAX_SS != _MIN_SS) */
+#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at _USE_MKFS == 1) */
+#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at _USE_TRIM == 1) */
+
+/* Generic command (Not used by FatFs) */
+#define CTRL_POWER 5 /* Get/Set power status */
+#define CTRL_LOCK 6 /* Lock/Unlock media removal */
+#define CTRL_EJECT 7 /* Eject media */
+#define CTRL_FORMAT 8 /* Create physical format on the media */
+
+/* MMC/SDC specific ioctl command */
+#define MMC_GET_TYPE 10 /* Get card type */
+#define MMC_GET_CSD 11 /* Get CSD */
+#define MMC_GET_CID 12 /* Get CID */
+#define MMC_GET_OCR 13 /* Get OCR */
+#define MMC_GET_SDSTAT 14 /* Get SD status */
+
+/* ATA/CF specific ioctl command */
+#define ATA_GET_REV 20 /* Get F/W revision */
+#define ATA_GET_MODEL 21 /* Get model name */
+#define ATA_GET_SN 22 /* Get serial number */
+
+
+#endif
diff --git a/emb/pastilda/fs/fatfs/ff.cpp b/emb/pastilda/fs/fatfs/ff.cpp
new file mode 100644
index 0000000..15aae64
--- /dev/null
+++ b/emb/pastilda/fs/fatfs/ff.cpp
@@ -0,0 +1,4635 @@
+/*----------------------------------------------------------------------------/
+/ FatFs - FAT file system module R0.11 (C)ChaN, 2015
+/-----------------------------------------------------------------------------/
+/ FatFs module is a free software that opened under license policy of
+/ following conditions.
+/
+/ Copyright (C) 2015, ChaN, all right reserved.
+/
+/ 1. Redistributions of source code must retain the above copyright notice,
+/ this condition and the following disclaimer.
+/
+/ This software is provided by the copyright holder and contributors "AS IS"
+/ and any warranties related to this software are DISCLAIMED.
+/ The copyright owner or contributors be NOT LIABLE for any damages caused
+/ by use of this software.
+/----------------------------------------------------------------------------*/
+
+
+#include <fs/fatfs/diskio.h> /* Declarations of disk I/O functions */
+#include <fs/fatfs/ff.h> /* Declarations of FatFs API */
+
+
+/*--------------------------------------------------------------------------
+
+ Module Private Definitions
+
+---------------------------------------------------------------------------*/
+
+#if _FATFS != 32020 /* Revision ID */
+#error Wrong include file (ff.h).
+#endif
+
+
+/* Reentrancy related */
+#if _FS_REENTRANT
+#if _USE_LFN == 1
+#error Static LFN work area cannot be used at thread-safe configuration
+#endif
+#define ENTER_FF(fs) { if (!lock_fs(fs)) return FR_TIMEOUT; }
+#define LEAVE_FF(fs, res) { unlock_fs(fs, res); return res; }
+#else
+#define ENTER_FF(fs)
+#define LEAVE_FF(fs, res) return res
+#endif
+
+#define ABORT(fs, res) { fp->err = (BYTE)(res); LEAVE_FF(fs, res); }
+
+
+/* Definitions of sector size */
+#if (_MAX_SS < _MIN_SS) || (_MAX_SS != 512 && _MAX_SS != 1024 && _MAX_SS != 2048 && _MAX_SS != 4096) || (_MIN_SS != 512 && _MIN_SS != 1024 && _MIN_SS != 2048 && _MIN_SS != 4096)
+#error Wrong sector size configuration
+#endif
+#if _MAX_SS == _MIN_SS
+#define SS(fs) ((UINT)_MAX_SS) /* Fixed sector size */
+#else
+#define SS(fs) ((fs)->ssize) /* Variable sector size */
+#endif
+
+
+/* Timestamp feature */
+#if _FS_NORTC == 1
+#if _NORTC_YEAR < 1980 || _NORTC_YEAR > 2107 || _NORTC_MON < 1 || _NORTC_MON > 12 || _NORTC_MDAY < 1 || _NORTC_MDAY > 31
+#error Invalid _FS_NORTC settings
+#endif
+#define GET_FATTIME() ((DWORD)(_NORTC_YEAR - 1980) << 25 | (DWORD)_NORTC_MON << 21 | (DWORD)_NORTC_MDAY << 16)
+#else
+#define GET_FATTIME() get_fattime()
+#endif
+
+
+/* File access control feature */
+#if _FS_LOCK
+#if _FS_READONLY
+#error _FS_LOCK must be 0 at read-only configuration
+#endif
+typedef struct {
+ FATFS *fs; /* Object ID 1, volume (NULL:blank entry) */
+ DWORD clu; /* Object ID 2, directory (0:root) */
+ WORD idx; /* Object ID 3, directory index */
+ WORD ctr; /* Object open counter, 0:none, 0x01..0xFF:read mode open count, 0x100:write mode */
+} FILESEM;
+#endif
+
+
+
+/* DBCS code ranges and SBCS extend character conversion table */
+
+#if _CODE_PAGE == 932 /* Japanese Shift-JIS */
+#define _DF1S 0x81 /* DBC 1st byte range 1 start */
+#define _DF1E 0x9F /* DBC 1st byte range 1 end */
+#define _DF2S 0xE0 /* DBC 1st byte range 2 start */
+#define _DF2E 0xFC /* DBC 1st byte range 2 end */
+#define _DS1S 0x40 /* DBC 2nd byte range 1 start */
+#define _DS1E 0x7E /* DBC 2nd byte range 1 end */
+#define _DS2S 0x80 /* DBC 2nd byte range 2 start */
+#define _DS2E 0xFC /* DBC 2nd byte range 2 end */
+
+#elif _CODE_PAGE == 936 /* Simplified Chinese GBK */
+#define _DF1S 0x81
+#define _DF1E 0xFE
+#define _DS1S 0x40
+#define _DS1E 0x7E
+#define _DS2S 0x80
+#define _DS2E 0xFE
+
+#elif _CODE_PAGE == 949 /* Korean */
+#define _DF1S 0x81
+#define _DF1E 0xFE
+#define _DS1S 0x41
+#define _DS1E 0x5A
+#define _DS2S 0x61
+#define _DS2E 0x7A
+#define _DS3S 0x81
+#define _DS3E 0xFE
+
+#elif _CODE_PAGE == 950 /* Traditional Chinese Big5 */
+#define _DF1S 0x81
+#define _DF1E 0xFE
+#define _DS1S 0x40
+#define _DS1E 0x7E
+#define _DS2S 0xA1
+#define _DS2E 0xFE
+
+#elif _CODE_PAGE == 437 /* U.S. (OEM) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F,0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+ 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 720 /* Arabic (OEM) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x45,0x41,0x84,0x41,0x86,0x43,0x45,0x45,0x45,0x49,0x49,0x8D,0x8E,0x8F,0x90,0x92,0x92,0x93,0x94,0x95,0x49,0x49,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+ 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 737 /* Greek (OEM) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x92,0x92,0x93,0x94,0x95,0x96,0x97,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, \
+ 0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0xAA,0x92,0x93,0x94,0x95,0x96,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0x97,0xEA,0xEB,0xEC,0xE4,0xED,0xEE,0xE7,0xE8,0xF1,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 775 /* Baltic (OEM) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x9A,0x91,0xA0,0x8E,0x95,0x8F,0x80,0xAD,0xED,0x8A,0x8A,0xA1,0x8D,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0x95,0x96,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \
+ 0xA0,0xA1,0xE0,0xA3,0xA3,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xA5,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE3,0xE8,0xE8,0xEA,0xEA,0xEE,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 850 /* Multilingual Latin 1 (OEM) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0xDE,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x59,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \
+ 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE7,0xE9,0xEA,0xEB,0xED,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 852 /* Latin 2 (OEM) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xDE,0x8F,0x80,0x9D,0xD3,0x8A,0x8A,0xD7,0x8D,0x8E,0x8F,0x90,0x91,0x91,0xE2,0x99,0x95,0x95,0x97,0x97,0x99,0x9A,0x9B,0x9B,0x9D,0x9E,0x9F, \
+ 0xB5,0xD6,0xE0,0xE9,0xA4,0xA4,0xA6,0xA6,0xA8,0xA8,0xAA,0x8D,0xAC,0xB8,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBD,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC6,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD2,0xD3,0xD2,0xD5,0xD6,0xD7,0xB7,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xE0,0xE1,0xE2,0xE3,0xE3,0xD5,0xE6,0xE6,0xE8,0xE9,0xE8,0xEB,0xED,0xED,0xDD,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xEB,0xFC,0xFC,0xFE,0xFF}
+
+#elif _CODE_PAGE == 855 /* Cyrillic (OEM) */
+#define _DF1S 0
+#define _EXCVT {0x81,0x81,0x83,0x83,0x85,0x85,0x87,0x87,0x89,0x89,0x8B,0x8B,0x8D,0x8D,0x8F,0x8F,0x91,0x91,0x93,0x93,0x95,0x95,0x97,0x97,0x99,0x99,0x9B,0x9B,0x9D,0x9D,0x9F,0x9F, \
+ 0xA1,0xA1,0xA3,0xA3,0xA5,0xA5,0xA7,0xA7,0xA9,0xA9,0xAB,0xAB,0xAD,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB6,0xB6,0xB8,0xB8,0xB9,0xBA,0xBB,0xBC,0xBE,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD3,0xD3,0xD5,0xD5,0xD7,0xD7,0xDD,0xD9,0xDA,0xDB,0xDC,0xDD,0xE0,0xDF, \
+ 0xE0,0xE2,0xE2,0xE4,0xE4,0xE6,0xE6,0xE8,0xE8,0xEA,0xEA,0xEC,0xEC,0xEE,0xEE,0xEF,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 857 /* Turkish (OEM) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0x98,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x98,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9E, \
+ 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA6,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xDE,0x59,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 858 /* Multilingual Latin 1 + Euro (OEM) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0xDE,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x59,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \
+ 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE7,0xE9,0xEA,0xEB,0xED,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 862 /* Hebrew (OEM) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+ 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 866 /* Russian (OEM) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0x90,0x91,0x92,0x93,0x9d,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 874 /* Thai (OEM, Windows) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+ 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 1250 /* Central Europe (Windows) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x8D,0x8E,0x8F, \
+ 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xA3,0xB4,0xB5,0xB6,0xB7,0xB8,0xA5,0xAA,0xBB,0xBC,0xBD,0xBC,0xAF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xFF}
+
+#elif _CODE_PAGE == 1251 /* Cyrillic (Windows) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x82,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x80,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x8D,0x8E,0x8F, \
+ 0xA0,0xA2,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB2,0xA5,0xB5,0xB6,0xB7,0xA8,0xB9,0xAA,0xBB,0xA3,0xBD,0xBD,0xAF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF}
+
+#elif _CODE_PAGE == 1252 /* Latin 1 (Windows) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0xAd,0x9B,0x8C,0x9D,0xAE,0x9F, \
+ 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x9F}
+
+#elif _CODE_PAGE == 1253 /* Greek (Windows) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+ 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xA2,0xB8,0xB9,0xBA, \
+ 0xE0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xF2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xFB,0xBC,0xFD,0xBF,0xFF}
+
+#elif _CODE_PAGE == 1254 /* Turkish (Windows) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x9D,0x9E,0x9F, \
+ 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x9F}
+
+#elif _CODE_PAGE == 1255 /* Hebrew (Windows) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+ 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 1256 /* Arabic (Windows) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x8C,0x9D,0x9E,0x9F, \
+ 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0x41,0xE1,0x41,0xE3,0xE4,0xE5,0xE6,0x43,0x45,0x45,0x45,0x45,0xEC,0xED,0x49,0x49,0xF0,0xF1,0xF2,0xF3,0x4F,0xF5,0xF6,0xF7,0xF8,0x55,0xFA,0x55,0x55,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 1257 /* Baltic (Windows) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+ 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xA8,0xB9,0xAA,0xBB,0xBC,0xBD,0xBE,0xAF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xFF}
+
+#elif _CODE_PAGE == 1258 /* Vietnam (OEM, Windows) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0xAC,0x9D,0x9E,0x9F, \
+ 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xEC,0xCD,0xCE,0xCF,0xD0,0xD1,0xF2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xFE,0x9F}
+
+#elif _CODE_PAGE == 1 /* ASCII (for only non-LFN cfg) */
+#if _USE_LFN
+#error Cannot use LFN feature without valid code page.
+#endif
+#define _DF1S 0
+
+#else
+#error Unknown code page
+
+#endif
+
+
+/* Character code support macros */
+#define IsUpper(c) (((c)>='A')&&((c)<='Z'))
+#define IsLower(c) (((c)>='a')&&((c)<='z'))
+#define IsDigit(c) (((c)>='0')&&((c)<='9'))
+
+#if _DF1S /* Code page is DBCS */
+
+#ifdef _DF2S /* Two 1st byte areas */
+#define IsDBCS1(c) (((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) || ((BYTE)(c) >= _DF2S && (BYTE)(c) <= _DF2E))
+#else /* One 1st byte area */
+#define IsDBCS1(c) ((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E)
+#endif
+
+#ifdef _DS3S /* Three 2nd byte areas */
+#define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E) || ((BYTE)(c) >= _DS3S && (BYTE)(c) <= _DS3E))
+#else /* Two 2nd byte areas */
+#define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E))
+#endif
+
+#else /* Code page is SBCS */
+
+#define IsDBCS1(c) 0
+#define IsDBCS2(c) 0
+
+#endif /* _DF1S */
+
+
+/* Name status flags */
+#define NSFLAG 11 /* Index of name status byte in fn[] */
+#define NS_LOSS 0x01 /* Out of 8.3 format */
+#define NS_LFN 0x02 /* Force to create LFN entry */
+#define NS_LAST 0x04 /* Last segment */
+#define NS_BODY 0x08 /* Lower case flag (body) */
+#define NS_EXT 0x10 /* Lower case flag (ext) */
+#define NS_DOT 0x20 /* Dot entry */
+
+
+/* FAT sub-type boundaries (Differ from specs but correct for real DOS/Windows) */
+#define MIN_FAT16 4086U /* Minimum number of clusters as FAT16 */
+#define MIN_FAT32 65526U /* Minimum number of clusters as FAT32 */
+
+
+/* FatFs refers the members in the FAT structures as byte array instead of
+/ structure member because the structure is not binary compatible between
+/ different platforms */
+
+#define BS_jmpBoot 0 /* x86 jump instruction (3) */
+#define BS_OEMName 3 /* OEM name (8) */
+#define BPB_BytsPerSec 11 /* Sector size [byte] (2) */
+#define BPB_SecPerClus 13 /* Cluster size [sector] (1) */
+#define BPB_RsvdSecCnt 14 /* Size of reserved area [sector] (2) */
+#define BPB_NumFATs 16 /* Number of FAT copies (1) */
+#define BPB_RootEntCnt 17 /* Number of root directory entries for FAT12/16 (2) */
+#define BPB_TotSec16 19 /* Volume size [sector] (2) */
+#define BPB_Media 21 /* Media descriptor (1) */
+#define BPB_FATSz16 22 /* FAT size [sector] (2) */
+#define BPB_SecPerTrk 24 /* Track size [sector] (2) */
+#define BPB_NumHeads 26 /* Number of heads (2) */
+#define BPB_HiddSec 28 /* Number of special hidden sectors (4) */
+#define BPB_TotSec32 32 /* Volume size [sector] (4) */
+#define BS_DrvNum 36 /* Physical drive number (2) */
+#define BS_BootSig 38 /* Extended boot signature (1) */
+#define BS_VolID 39 /* Volume serial number (4) */
+#define BS_VolLab 43 /* Volume label (8) */
+#define BS_FilSysType 54 /* File system type (1) */
+#define BPB_FATSz32 36 /* FAT size [sector] (4) */
+#define BPB_ExtFlags 40 /* Extended flags (2) */
+#define BPB_FSVer 42 /* File system version (2) */
+#define BPB_RootClus 44 /* Root directory first cluster (4) */
+#define BPB_FSInfo 48 /* Offset of FSINFO sector (2) */
+#define BPB_BkBootSec 50 /* Offset of backup boot sector (2) */
+#define BS_DrvNum32 64 /* Physical drive number (2) */
+#define BS_BootSig32 66 /* Extended boot signature (1) */
+#define BS_VolID32 67 /* Volume serial number (4) */
+#define BS_VolLab32 71 /* Volume label (8) */
+#define BS_FilSysType32 82 /* File system type (1) */
+#define FSI_LeadSig 0 /* FSI: Leading signature (4) */
+#define FSI_StrucSig 484 /* FSI: Structure signature (4) */
+#define FSI_Free_Count 488 /* FSI: Number of free clusters (4) */
+#define FSI_Nxt_Free 492 /* FSI: Last allocated cluster (4) */
+#define MBR_Table 446 /* MBR: Partition table offset (2) */
+#define SZ_PTE 16 /* MBR: Size of a partition table entry */
+#define BS_55AA 510 /* Signature word (2) */
+
+#define DIR_Name 0 /* Short file name (11) */
+#define DIR_Attr 11 /* Attribute (1) */
+#define DIR_NTres 12 /* Lower case flag (1) */
+#define DIR_CrtTimeTenth 13 /* Created time sub-second (1) */
+#define DIR_CrtTime 14 /* Created time (2) */
+#define DIR_CrtDate 16 /* Created date (2) */
+#define DIR_LstAccDate 18 /* Last accessed date (2) */
+#define DIR_FstClusHI 20 /* Higher 16-bit of first cluster (2) */
+#define DIR_WrtTime 22 /* Modified time (2) */
+#define DIR_WrtDate 24 /* Modified date (2) */
+#define DIR_FstClusLO 26 /* Lower 16-bit of first cluster (2) */
+#define DIR_FileSize 28 /* File size (4) */
+#define LDIR_Ord 0 /* LFN entry order and LLE flag (1) */
+#define LDIR_Attr 11 /* LFN attribute (1) */
+#define LDIR_Type 12 /* LFN type (1) */
+#define LDIR_Chksum 13 /* Sum of corresponding SFN entry */
+#define LDIR_FstClusLO 26 /* Must be zero (0) */
+#define SZ_DIRE 32 /* Size of a directory entry */
+#define LLEF 0x40 /* Last long entry flag in LDIR_Ord */
+#define DDEM 0xE5 /* Deleted directory entry mark at DIR_Name[0] */
+#define RDDEM 0x05 /* Replacement of the character collides with DDEM */
+
+
+
+
+/*------------------------------------------------------------*/
+/* Module private work area */
+/*------------------------------------------------------------*/
+/* Remark: Uninitialized variables with static duration are
+/ guaranteed zero/null at start-up. If not, either the linker
+/ or start-up routine being used is out of ANSI-C standard.
+*/
+
+#if _VOLUMES < 1 || _VOLUMES > 9
+#error Wrong _VOLUMES setting
+#endif
+static FATFS *FatFs[_VOLUMES]; /* Pointer to the file system objects (logical drives) */
+static WORD Fsid; /* File system mount ID */
+
+#if _FS_RPATH && _VOLUMES >= 2
+static BYTE CurrVol; /* Current drive */
+#endif
+
+#if _FS_LOCK
+static FILESEM Files[_FS_LOCK]; /* Open object lock semaphores */
+#endif
+
+#if _USE_LFN == 0 /* Non LFN feature */
+#define DEFINE_NAMEBUF BYTE sfn[12]
+#define INIT_BUF(dobj) (dobj).fn = sfn
+#define FREE_BUF()
+#else
+#if _MAX_LFN < 12 || _MAX_LFN > 255
+#error Wrong _MAX_LFN setting
+#endif
+#if _USE_LFN == 1 /* LFN feature with static working buffer */
+static WCHAR LfnBuf[_MAX_LFN + 1];
+#define DEFINE_NAMEBUF BYTE sfn[12]
+#define INIT_BUF(dobj) { (dobj).fn = sfn; (dobj).lfn = LfnBuf; }
+#define FREE_BUF()
+#elif _USE_LFN == 2 /* LFN feature with dynamic working buffer on the stack */
+#define DEFINE_NAMEBUF BYTE sfn[12]; WCHAR lbuf[_MAX_LFN + 1]
+#define INIT_BUF(dobj) { (dobj).fn = sfn; (dobj).lfn = lbuf; }
+#define FREE_BUF()
+#elif _USE_LFN == 3 /* LFN feature with dynamic working buffer on the heap */
+#define DEFINE_NAMEBUF BYTE sfn[12]; WCHAR *lfn
+#define INIT_BUF(dobj) { lfn = ff_memalloc((_MAX_LFN + 1) * 2); if (!lfn) LEAVE_FF((dobj).fs, FR_NOT_ENOUGH_CORE); (dobj).lfn = lfn; (dobj).fn = sfn; }
+#define FREE_BUF() ff_memfree(lfn)
+#else
+#error Wrong _USE_LFN setting
+#endif
+#endif
+
+#ifdef _EXCVT
+static const BYTE ExCvt[] = _EXCVT; /* Upper conversion table for extended characters */
+#endif
+
+
+
+
+
+
+/*--------------------------------------------------------------------------
+
+ Module Private Functions
+
+---------------------------------------------------------------------------*/
+
+
+/*-----------------------------------------------------------------------*/
+/* String functions */
+/*-----------------------------------------------------------------------*/
+
+/* Copy memory to memory */
+static
+void mem_cpy (void* dst, const void* src, UINT cnt) {
+ BYTE *d = (BYTE*)dst;
+ const BYTE *s = (const BYTE*)src;
+
+#if _WORD_ACCESS == 1
+ while (cnt >= sizeof (int)) {
+ *(int*)d = *(int*)s;
+ d += sizeof (int); s += sizeof (int);
+ cnt -= sizeof (int);
+ }
+#endif
+ while (cnt--)
+ *d++ = *s++;
+}
+
+/* Fill memory */
+static
+void mem_set (void* dst, int val, UINT cnt) {
+ BYTE *d = (BYTE*)dst;
+
+ while (cnt--)
+ *d++ = (BYTE)val;
+}
+
+/* Compare memory to memory */
+static
+int mem_cmp (const void* dst, const void* src, UINT cnt) {
+ const BYTE *d = (const BYTE *)dst, *s = (const BYTE *)src;
+ int r = 0;
+
+ while (cnt-- && (r = *d++ - *s++) == 0) ;
+ return r;
+}
+
+/* Check if chr is contained in the string */
+static
+int chk_chr (const char* str, int chr) {
+ while (*str && *str != chr) str++;
+ return *str;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Request/Release grant to access the volume */
+/*-----------------------------------------------------------------------*/
+#if _FS_REENTRANT
+static
+int lock_fs (
+ FATFS* fs /* File system object */
+)
+{
+ return ff_req_grant(fs->sobj);
+}
+
+
+static
+void unlock_fs (
+ FATFS* fs, /* File system object */
+ FRESULT res /* Result code to be returned */
+)
+{
+ if (fs &&
+ res != FR_NOT_ENABLED &&
+ res != FR_INVALID_DRIVE &&
+ res != FR_INVALID_OBJECT &&
+ res != FR_TIMEOUT) {
+ ff_rel_grant(fs->sobj);
+ }
+}
+#endif
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* File lock control functions */
+/*-----------------------------------------------------------------------*/
+#if _FS_LOCK
+
+static
+FRESULT chk_lock ( /* Check if the file can be accessed */
+ DIR* dp, /* Directory object pointing the file to be checked */
+ int acc /* Desired access type (0:Read, 1:Write, 2:Delete/Rename) */
+)
+{
+ UINT i, be;
+
+ /* Search file semaphore table */
+ for (i = be = 0; i < _FS_LOCK; i++) {
+ if (Files[i].fs) { /* Existing entry */
+ if (Files[i].fs == dp->fs && /* Check if the object matched with an open object */
+ Files[i].clu == dp->sclust &&
+ Files[i].idx == dp->index) break;
+ } else { /* Blank entry */
+ be = 1;
+ }
+ }
+ if (i == _FS_LOCK) /* The object is not opened */
+ return (be || acc == 2) ? FR_OK : FR_TOO_MANY_OPEN_FILES; /* Is there a blank entry for new object? */
+
+ /* The object has been opened. Reject any open against writing file and all write mode open */
+ return (acc || Files[i].ctr == 0x100) ? FR_LOCKED : FR_OK;
+}
+
+
+static
+int enq_lock (void) /* Check if an entry is available for a new object */
+{
+ UINT i;
+
+ for (i = 0; i < _FS_LOCK && Files[i].fs; i++) ;
+ return (i == _FS_LOCK) ? 0 : 1;
+}
+
+
+static
+UINT inc_lock ( /* Increment object open counter and returns its index (0:Internal error) */
+ DIR* dp, /* Directory object pointing the file to register or increment */
+ int acc /* Desired access (0:Read, 1:Write, 2:Delete/Rename) */
+)
+{
+ UINT i;
+
+
+ for (i = 0; i < _FS_LOCK; i++) { /* Find the object */
+ if (Files[i].fs == dp->fs &&
+ Files[i].clu == dp->sclust &&
+ Files[i].idx == dp->index) break;
+ }
+
+ if (i == _FS_LOCK) { /* Not opened. Register it as new. */
+ for (i = 0; i < _FS_LOCK && Files[i].fs; i++) ;
+ if (i == _FS_LOCK) return 0; /* No free entry to register (int err) */
+ Files[i].fs = dp->fs;
+ Files[i].clu = dp->sclust;
+ Files[i].idx = dp->index;
+ Files[i].ctr = 0;
+ }
+
+ if (acc && Files[i].ctr) return 0; /* Access violation (int err) */
+
+ Files[i].ctr = acc ? 0x100 : Files[i].ctr + 1; /* Set semaphore value */
+
+ return i + 1;
+}
+
+
+static
+FRESULT dec_lock ( /* Decrement object open counter */
+ UINT i /* Semaphore index (1..) */
+)
+{
+ WORD n;
+ FRESULT res;
+
+
+ if (--i < _FS_LOCK) { /* Shift index number origin from 0 */
+ n = Files[i].ctr;
+ if (n == 0x100) n = 0; /* If write mode open, delete the entry */
+ if (n) n--; /* Decrement read mode open count */
+ Files[i].ctr = n;
+ if (!n) Files[i].fs = 0; /* Delete the entry if open count gets zero */
+ res = FR_OK;
+ } else {
+ res = FR_INT_ERR; /* Invalid index nunber */
+ }
+ return res;
+}
+
+
+static
+void clear_lock ( /* Clear lock entries of the volume */
+ FATFS *fs
+)
+{
+ UINT i;
+
+ for (i = 0; i < _FS_LOCK; i++) {
+ if (Files[i].fs == fs) Files[i].fs = 0;
+ }
+}
+#endif
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Move/Flush disk access window in the file system object */
+/*-----------------------------------------------------------------------*/
+#if !_FS_READONLY
+static
+FRESULT sync_window (
+ FATFS* fs /* File system object */
+)
+{
+ DWORD wsect;
+ UINT nf;
+ FRESULT res = FR_OK;
+
+
+ if (fs->wflag) { /* Write back the sector if it is dirty */
+ wsect = fs->winsect; /* Current sector number */
+ if (disk_write(fs->drv, fs->win, wsect, 1) != RES_OK) {
+ res = FR_DISK_ERR;
+ } else {
+ fs->wflag = 0;
+ if (wsect - fs->fatbase < fs->fsize) { /* Is it in the FAT area? */
+ for (nf = fs->n_fats; nf >= 2; nf--) { /* Reflect the change to all FAT copies */
+ wsect += fs->fsize;
+ disk_write(fs->drv, fs->win, wsect, 1);
+ }
+ }
+ }
+ }
+ return res;
+}
+#endif
+
+
+static
+FRESULT move_window (
+ FATFS* fs, /* File system object */
+ DWORD sector /* Sector number to make appearance in the fs->win[] */
+)
+{
+ FRESULT res = FR_OK;
+
+
+ if (sector != fs->winsect) { /* Window offset changed? */
+#if !_FS_READONLY
+ res = sync_window(fs); /* Write-back changes */
+#endif
+ if (res == FR_OK) { /* Fill sector window with new data */
+ if (disk_read(fs->drv, fs->win, sector, 1) != RES_OK) {
+ sector = 0xFFFFFFFF; /* Invalidate window if data is not reliable */
+ res = FR_DISK_ERR;
+ }
+ fs->winsect = sector;
+ }
+ }
+ return res;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Synchronize file system and strage device */
+/*-----------------------------------------------------------------------*/
+#if !_FS_READONLY
+static
+FRESULT sync_fs ( /* FR_OK: successful, FR_DISK_ERR: failed */
+ FATFS* fs /* File system object */
+)
+{
+ FRESULT res;
+
+
+ res = sync_window(fs);
+ if (res == FR_OK) {
+ /* Update FSINFO sector if needed */
+ if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) {
+ /* Create FSINFO structure */
+ mem_set(fs->win, 0, SS(fs));
+ ST_WORD(fs->win + BS_55AA, 0xAA55);
+ ST_DWORD(fs->win + FSI_LeadSig, 0x41615252);
+ ST_DWORD(fs->win + FSI_StrucSig, 0x61417272);
+ ST_DWORD(fs->win + FSI_Free_Count, fs->free_clust);
+ ST_DWORD(fs->win + FSI_Nxt_Free, fs->last_clust);
+ /* Write it into the FSINFO sector */
+ fs->winsect = fs->volbase + 1;
+ disk_write(fs->drv, fs->win, fs->winsect, 1);
+ fs->fsi_flag = 0;
+ }
+ /* Make sure that no pending write process in the physical drive */
+ if (disk_ioctl(fs->drv, CTRL_SYNC, 0) != RES_OK)
+ res = FR_DISK_ERR;
+ }
+
+ return res;
+}
+#endif
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Get sector# from cluster# */
+/*-----------------------------------------------------------------------*/
+/* Hidden API for hacks and disk tools */
+
+DWORD clust2sect ( /* !=0: Sector number, 0: Failed - invalid cluster# */
+ FATFS* fs, /* File system object */
+ DWORD clst /* Cluster# to be converted */
+)
+{
+ clst -= 2;
+ if (clst >= fs->n_fatent - 2) return 0; /* Invalid cluster# */
+ return clst * fs->csize + fs->database;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* FAT access - Read value of a FAT entry */
+/*-----------------------------------------------------------------------*/
+/* Hidden API for hacks and disk tools */
+
+DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x0FFFFFFF:Cluster status */
+ FATFS* fs, /* File system object */
+ DWORD clst /* FAT index number (cluster number) to get the value */
+)
+{
+ UINT wc, bc;
+ BYTE *p;
+ DWORD val;
+
+
+ if (clst < 2 || clst >= fs->n_fatent) { /* Check range */
+ val = 1; /* Internal error */
+
+ } else {
+ val = 0xFFFFFFFF; /* Default value falls on disk error */
+
+ switch (fs->fs_type) {
+ case FS_FAT12 :
+ bc = (UINT)clst; bc += bc / 2;
+ if (move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK) break;
+ wc = fs->win[bc++ % SS(fs)];
+ if (move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK) break;
+ wc |= fs->win[bc % SS(fs)] << 8;
+ val = clst & 1 ? wc >> 4 : (wc & 0xFFF);
+ break;
+
+ case FS_FAT16 :
+ if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))) != FR_OK) break;
+ p = &fs->win[clst * 2 % SS(fs)];
+ val = LD_WORD(p);
+ break;
+
+ case FS_FAT32 :
+ if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break;
+ p = &fs->win[clst * 4 % SS(fs)];
+ val = LD_DWORD(p) & 0x0FFFFFFF;
+ break;
+
+ default:
+ val = 1; /* Internal error */
+ }
+ }
+
+ return val;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* FAT access - Change value of a FAT entry */
+/*-----------------------------------------------------------------------*/
+/* Hidden API for hacks and disk tools */
+
+#if !_FS_READONLY
+FRESULT put_fat (
+ FATFS* fs, /* File system object */
+ DWORD clst, /* FAT index number (cluster number) to be changed */
+ DWORD val /* New value to be set to the entry */
+)
+{
+ UINT bc;
+ BYTE *p;
+ FRESULT res;
+
+
+ if (clst < 2 || clst >= fs->n_fatent) { /* Check range */
+ res = FR_INT_ERR;
+
+ } else {
+ switch (fs->fs_type) {
+ case FS_FAT12 :
+ bc = (UINT)clst; bc += bc / 2;
+ res = move_window(fs, fs->fatbase + (bc / SS(fs)));
+ if (res != FR_OK) break;
+ p = &fs->win[bc++ % SS(fs)];
+ *p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val;
+ fs->wflag = 1;
+ res = move_window(fs, fs->fatbase + (bc / SS(fs)));
+ if (res != FR_OK) break;
+ p = &fs->win[bc % SS(fs)];
+ *p = (clst & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F));
+ fs->wflag = 1;
+ break;
+
+ case FS_FAT16 :
+ res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 2)));
+ if (res != FR_OK) break;
+ p = &fs->win[clst * 2 % SS(fs)];
+ ST_WORD(p, (WORD)val);
+ fs->wflag = 1;
+ break;
+
+ case FS_FAT32 :
+ res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 4)));
+ if (res != FR_OK) break;
+ p = &fs->win[clst * 4 % SS(fs)];
+ val |= LD_DWORD(p) & 0xF0000000;
+ ST_DWORD(p, val);
+ fs->wflag = 1;
+ break;
+
+ default :
+ res = FR_INT_ERR;
+ }
+ }
+
+ return res;
+}
+#endif /* !_FS_READONLY */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* FAT handling - Remove a cluster chain */
+/*-----------------------------------------------------------------------*/
+#if !_FS_READONLY
+static
+FRESULT remove_chain (
+ FATFS* fs, /* File system object */
+ DWORD clst /* Cluster# to remove a chain from */
+)
+{
+ FRESULT res;
+ DWORD nxt;
+#if _USE_TRIM
+ DWORD scl = clst, ecl = clst, rt[2];
+#endif
+
+ if (clst < 2 || clst >= fs->n_fatent) { /* Check range */
+ res = FR_INT_ERR;
+
+ } else {
+ res = FR_OK;
+ while (clst < fs->n_fatent) { /* Not a last link? */
+ nxt = get_fat(fs, clst); /* Get cluster status */
+ if (nxt == 0) break; /* Empty cluster? */
+ if (nxt == 1) { res = FR_INT_ERR; break; } /* Internal error? */
+ if (nxt == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } /* Disk error? */
+ res = put_fat(fs, clst, 0); /* Mark the cluster "empty" */
+ if (res != FR_OK) break;
+ if (fs->free_clust != 0xFFFFFFFF) { /* Update FSINFO */
+ fs->free_clust++;
+ fs->fsi_flag |= 1;
+ }
+#if _USE_TRIM
+ if (ecl + 1 == nxt) { /* Is next cluster contiguous? */
+ ecl = nxt;
+ } else { /* End of contiguous clusters */
+ rt[0] = clust2sect(fs, scl); /* Start sector */
+ rt[1] = clust2sect(fs, ecl) + fs->csize - 1; /* End sector */
+ disk_ioctl(fs->drv, CTRL_TRIM, rt); /* Erase the block */
+ scl = ecl = nxt;
+ }
+#endif
+ clst = nxt; /* Next cluster */
+ }
+ }
+
+ return res;
+}
+#endif
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* FAT handling - Stretch or Create a cluster chain */
+/*-----------------------------------------------------------------------*/
+#if !_FS_READONLY
+static
+DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */
+ FATFS* fs, /* File system object */
+ DWORD clst /* Cluster# to stretch. 0 means create a new chain. */
+)
+{
+ DWORD cs, ncl, scl;
+ FRESULT res;
+
+
+ if (clst == 0) { /* Create a new chain */
+ scl = fs->last_clust; /* Get suggested start point */
+ if (!scl || scl >= fs->n_fatent) scl = 1;
+ }
+ else { /* Stretch the current chain */
+ cs = get_fat(fs, clst); /* Check the cluster status */
+ if (cs < 2) return 1; /* Invalid value */
+ if (cs == 0xFFFFFFFF) return cs; /* A disk error occurred */
+ if (cs < fs->n_fatent) return cs; /* It is already followed by next cluster */
+ scl = clst;
+ }
+
+ ncl = scl; /* Start cluster */
+ for (;;) {
+ ncl++; /* Next cluster */
+ if (ncl >= fs->n_fatent) { /* Check wrap around */
+ ncl = 2;
+ if (ncl > scl) return 0; /* No free cluster */
+ }
+ cs = get_fat(fs, ncl); /* Get the cluster status */
+ if (cs == 0) break; /* Found a free cluster */
+ if (cs == 0xFFFFFFFF || cs == 1)/* An error occurred */
+ return cs;
+ if (ncl == scl) return 0; /* No free cluster */
+ }
+
+ res = put_fat(fs, ncl, 0x0FFFFFFF); /* Mark the new cluster "last link" */
+ if (res == FR_OK && clst != 0) {
+ res = put_fat(fs, clst, ncl); /* Link it to the previous one if needed */
+ }
+ if (res == FR_OK) {
+ fs->last_clust = ncl; /* Update FSINFO */
+ if (fs->free_clust != 0xFFFFFFFF) {
+ fs->free_clust--;
+ fs->fsi_flag |= 1;
+ }
+ } else {
+ ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1;
+ }
+
+ return ncl; /* Return new cluster number or error code */
+}
+#endif /* !_FS_READONLY */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* FAT handling - Convert offset into cluster with link map table */
+/*-----------------------------------------------------------------------*/
+
+#if _USE_FASTSEEK
+static
+DWORD clmt_clust ( /* <2:Error, >=2:Cluster number */
+ FIL* fp, /* Pointer to the file object */
+ DWORD ofs /* File offset to be converted to cluster# */
+)
+{
+ DWORD cl, ncl, *tbl;
+
+
+ tbl = fp->cltbl + 1; /* Top of CLMT */
+ cl = ofs / SS(fp->fs) / fp->fs->csize; /* Cluster order from top of the file */
+ for (;;) {
+ ncl = *tbl++; /* Number of cluters in the fragment */
+ if (!ncl) return 0; /* End of table? (error) */
+ if (cl < ncl) break; /* In this fragment? */
+ cl -= ncl; tbl++; /* Next fragment */
+ }
+ return cl + *tbl; /* Return the cluster number */
+}
+#endif /* _USE_FASTSEEK */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Directory handling - Set directory index */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT dir_sdi (
+ DIR* dp, /* Pointer to directory object */
+ UINT idx /* Index of directory table */
+)
+{
+ DWORD clst, sect;
+ UINT ic;
+
+
+ dp->index = (WORD)idx; /* Current index */
+ clst = dp->sclust; /* Table start cluster (0:root) */
+ if (clst == 1 || clst >= dp->fs->n_fatent) /* Check start cluster range */
+ return FR_INT_ERR;
+ if (!clst && dp->fs->fs_type == FS_FAT32) /* Replace cluster# 0 with root cluster# if in FAT32 */
+ clst = dp->fs->dirbase;
+
+ if (clst == 0) { /* Static table (root-directory in FAT12/16) */
+ if (idx >= dp->fs->n_rootdir) /* Is index out of range? */
+ return FR_INT_ERR;
+ sect = dp->fs->dirbase;
+ }
+ else { /* Dynamic table (root-directory in FAT32 or sub-directory) */
+ ic = SS(dp->fs) / SZ_DIRE * dp->fs->csize; /* Entries per cluster */
+ while (idx >= ic) { /* Follow cluster chain */
+ clst = get_fat(dp->fs, clst); /* Get next cluster */
+ if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */
+ if (clst < 2 || clst >= dp->fs->n_fatent) /* Reached to end of table or internal error */
+ return FR_INT_ERR;
+ idx -= ic;
+ }
+ sect = clust2sect(dp->fs, clst);
+ }
+ dp->clust = clst; /* Current cluster# */
+ if (!sect) return FR_INT_ERR;
+ dp->sect = sect + idx / (SS(dp->fs) / SZ_DIRE); /* Sector# of the directory entry */
+ dp->dir = dp->fs->win + (idx % (SS(dp->fs) / SZ_DIRE)) * SZ_DIRE; /* Ptr to the entry in the sector */
+
+ return FR_OK;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Directory handling - Move directory table index next */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT dir_next ( /* FR_OK:Succeeded, FR_NO_FILE:End of table, FR_DENIED:Could not stretch */
+ DIR* dp, /* Pointer to the directory object */
+ int stretch /* 0: Do not stretch table, 1: Stretch table if needed */
+)
+{
+ DWORD clst;
+ UINT i;
+#if !_FS_READONLY
+ UINT c;
+#endif
+
+
+ i = dp->index + 1;
+ if (!(i & 0xFFFF) || !dp->sect) /* Report EOT when index has reached 65535 */
+ return FR_NO_FILE;
+
+ if (!(i % (SS(dp->fs) / SZ_DIRE))) { /* Sector changed? */
+ dp->sect++; /* Next sector */
+
+ if (!dp->clust) { /* Static table */
+ if (i >= dp->fs->n_rootdir) /* Report EOT if it reached end of static table */
+ return FR_NO_FILE;
+ }
+ else { /* Dynamic table */
+ if (((i / (SS(dp->fs) / SZ_DIRE)) & (dp->fs->csize - 1)) == 0) { /* Cluster changed? */
+ clst = get_fat(dp->fs, dp->clust); /* Get next cluster */
+ if (clst <= 1) return FR_INT_ERR;
+ if (clst == 0xFFFFFFFF) return FR_DISK_ERR;
+ if (clst >= dp->fs->n_fatent) { /* If it reached end of dynamic table, */
+#if !_FS_READONLY
+ if (!stretch) return FR_NO_FILE; /* If do not stretch, report EOT */
+ clst = create_chain(dp->fs, dp->clust); /* Stretch cluster chain */
+ if (clst == 0) return FR_DENIED; /* No free cluster */
+ if (clst == 1) return FR_INT_ERR;
+ if (clst == 0xFFFFFFFF) return FR_DISK_ERR;
+ /* Clean-up stretched table */
+ if (sync_window(dp->fs)) return FR_DISK_ERR;/* Flush disk access window */
+ mem_set(dp->fs->win, 0, SS(dp->fs)); /* Clear window buffer */
+ dp->fs->winsect = clust2sect(dp->fs, clst); /* Cluster start sector */
+ for (c = 0; c < dp->fs->csize; c++) { /* Fill the new cluster with 0 */
+ dp->fs->wflag = 1;
+ if (sync_window(dp->fs)) return FR_DISK_ERR;
+ dp->fs->winsect++;
+ }
+ dp->fs->winsect -= c; /* Rewind window offset */
+#else
+ if (!stretch) return FR_NO_FILE; /* If do not stretch, report EOT (this is to suppress warning) */
+ return FR_NO_FILE; /* Report EOT */
+#endif
+ }
+ dp->clust = clst; /* Initialize data for new cluster */
+ dp->sect = clust2sect(dp->fs, clst);
+ }
+ }
+ }
+
+ dp->index = (WORD)i; /* Current index */
+ dp->dir = dp->fs->win + (i % (SS(dp->fs) / SZ_DIRE)) * SZ_DIRE; /* Current entry in the window */
+
+ return FR_OK;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Directory handling - Reserve directory entry */
+/*-----------------------------------------------------------------------*/
+
+#if !_FS_READONLY
+static
+FRESULT dir_alloc (
+ DIR* dp, /* Pointer to the directory object */
+ UINT nent /* Number of contiguous entries to allocate (1-21) */
+)
+{
+ FRESULT res;
+ UINT n;
+
+
+ res = dir_sdi(dp, 0);
+ if (res == FR_OK) {
+ n = 0;
+ do {
+ res = move_window(dp->fs, dp->sect);
+ if (res != FR_OK) break;
+ if (dp->dir[0] == DDEM || dp->dir[0] == 0) { /* Is it a free entry? */
+ if (++n == nent) break; /* A block of contiguous free entries is found */
+ } else {
+ n = 0; /* Not a blank entry. Restart to search */
+ }
+ res = dir_next(dp, 1); /* Next entry with table stretch enabled */
+ } while (res == FR_OK);
+ }
+ if (res == FR_NO_FILE) res = FR_DENIED; /* No directory entry to allocate */
+ return res;
+}
+#endif
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Directory handling - Load/Store start cluster number */
+/*-----------------------------------------------------------------------*/
+
+static
+DWORD ld_clust (
+ FATFS* fs, /* Pointer to the fs object */
+ BYTE* dir /* Pointer to the directory entry */
+)
+{
+ DWORD cl;
+
+ cl = LD_WORD(dir + DIR_FstClusLO);
+ if (fs->fs_type == FS_FAT32)
+ cl |= (DWORD)LD_WORD(dir + DIR_FstClusHI) << 16;
+
+ return cl;
+}
+
+
+#if !_FS_READONLY
+static
+void st_clust (
+ BYTE* dir, /* Pointer to the directory entry */
+ DWORD cl /* Value to be set */
+)
+{
+ ST_WORD(dir + DIR_FstClusLO, cl);
+ ST_WORD(dir + DIR_FstClusHI, cl >> 16);
+}
+#endif
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* LFN handling - Test/Pick/Fit an LFN segment from/to directory entry */
+/*-----------------------------------------------------------------------*/
+#if _USE_LFN
+static
+const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30}; /* Offset of LFN characters in the directory entry */
+
+
+static
+int cmp_lfn ( /* 1:Matched, 0:Not matched */
+ WCHAR* lfnbuf, /* Pointer to the LFN to be compared */
+ BYTE* dir /* Pointer to the directory entry containing a part of LFN */
+)
+{
+ UINT i, s;
+ WCHAR wc, uc;
+
+
+ i = ((dir[LDIR_Ord] & ~LLEF) - 1) * 13; /* Get offset in the LFN buffer */
+ s = 0; wc = 1;
+ do {
+ uc = LD_WORD(dir + LfnOfs[s]); /* Pick an LFN character from the entry */
+ if (wc) { /* Last character has not been processed */
+ wc = ff_wtoupper(uc); /* Convert it to upper case */
+ if (i >= _MAX_LFN || wc != ff_wtoupper(lfnbuf[i++])) /* Compare it */
+ return 0; /* Not matched */
+ } else {
+ if (uc != 0xFFFF) return 0; /* Check filler */
+ }
+ } while (++s < 13); /* Repeat until all characters in the entry are checked */
+
+ if ((dir[LDIR_Ord] & LLEF) && wc && lfnbuf[i]) /* Last segment matched but different length */
+ return 0;
+
+ return 1; /* The part of LFN matched */
+}
+
+
+
+static
+int pick_lfn ( /* 1:Succeeded, 0:Buffer overflow */
+ WCHAR* lfnbuf, /* Pointer to the Unicode-LFN buffer */
+ BYTE* dir /* Pointer to the directory entry */
+)
+{
+ UINT i, s;
+ WCHAR wc, uc;
+
+
+ i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */
+
+ s = 0; wc = 1;
+ do {
+ uc = LD_WORD(dir + LfnOfs[s]); /* Pick an LFN character from the entry */
+ if (wc) { /* Last character has not been processed */
+ if (i >= _MAX_LFN) return 0; /* Buffer overflow? */
+ lfnbuf[i++] = wc = uc; /* Store it */
+ } else {
+ if (uc != 0xFFFF) return 0; /* Check filler */
+ }
+ } while (++s < 13); /* Read all character in the entry */
+
+ if (dir[LDIR_Ord] & LLEF) { /* Put terminator if it is the last LFN part */
+ if (i >= _MAX_LFN) return 0; /* Buffer overflow? */
+ lfnbuf[i] = 0;
+ }
+
+ return 1;
+}
+
+
+#if !_FS_READONLY
+static
+void fit_lfn (
+ const WCHAR* lfnbuf, /* Pointer to the LFN buffer */
+ BYTE* dir, /* Pointer to the directory entry */
+ BYTE ord, /* LFN order (1-20) */
+ BYTE sum /* SFN sum */
+)
+{
+ UINT i, s;
+ WCHAR wc;
+
+
+ dir[LDIR_Chksum] = sum; /* Set check sum */
+ dir[LDIR_Attr] = AM_LFN; /* Set attribute. LFN entry */
+ dir[LDIR_Type] = 0;
+ ST_WORD(dir + LDIR_FstClusLO, 0);
+
+ i = (ord - 1) * 13; /* Get offset in the LFN buffer */
+ s = wc = 0;
+ do {
+ if (wc != 0xFFFF) wc = lfnbuf[i++]; /* Get an effective character */
+ ST_WORD(dir+LfnOfs[s], wc); /* Put it */
+ if (!wc) wc = 0xFFFF; /* Padding characters following last character */
+ } while (++s < 13);
+ if (wc == 0xFFFF || !lfnbuf[i]) ord |= LLEF; /* Bottom LFN part is the start of LFN sequence */
+ dir[LDIR_Ord] = ord; /* Set the LFN order */
+}
+
+#endif
+#endif
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Create numbered name */
+/*-----------------------------------------------------------------------*/
+#if _USE_LFN
+static
+void gen_numname (
+ BYTE* dst, /* Pointer to the buffer to store numbered SFN */
+ const BYTE* src, /* Pointer to SFN */
+ const WCHAR* lfn, /* Pointer to LFN */
+ UINT seq /* Sequence number */
+)
+{
+ BYTE ns[8], c;
+ UINT i, j;
+ WCHAR wc;
+ DWORD sr;
+
+
+ mem_cpy(dst, src, 11);
+
+ if (seq > 5) { /* On many collisions, generate a hash number instead of sequential number */
+ sr = seq;
+ while (*lfn) { /* Create a CRC */
+ wc = *lfn++;
+ for (i = 0; i < 16; i++) {
+ sr = (sr << 1) + (wc & 1);
+ wc >>= 1;
+ if (sr & 0x10000) sr ^= 0x11021;
+ }
+ }
+ seq = (UINT)sr;
+ }
+
+ /* itoa (hexdecimal) */
+ i = 7;
+ do {
+ c = (seq % 16) + '0';
+ if (c > '9') c += 7;
+ ns[i--] = c;
+ seq /= 16;
+ } while (seq);
+ ns[i] = '~';
+
+ /* Append the number */
+ for (j = 0; j < i && dst[j] != ' '; j++) {
+ if (IsDBCS1(dst[j])) {
+ if (j == i - 1) break;
+ j++;
+ }
+ }
+ do {
+ dst[j++] = (i < 8) ? ns[i++] : ' ';
+ } while (j < 8);
+}
+#endif
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Calculate sum of an SFN */
+/*-----------------------------------------------------------------------*/
+#if _USE_LFN
+static
+BYTE sum_sfn (
+ const BYTE* dir /* Pointer to the SFN entry */
+)
+{
+ BYTE sum = 0;
+ UINT n = 11;
+
+ do sum = (sum >> 1) + (sum << 7) + *dir++; while (--n);
+ return sum;
+}
+#endif
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Directory handling - Find an object in the directory */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT dir_find (
+ DIR* dp /* Pointer to the directory object linked to the file name */
+)
+{
+ FRESULT res;
+ BYTE c, *dir;
+#if _USE_LFN
+ BYTE a, ord, sum;
+#endif
+
+ res = dir_sdi(dp, 0); /* Rewind directory object */
+ if (res != FR_OK) return res;
+
+#if _USE_LFN
+ ord = sum = 0xFF; dp->lfn_idx = 0xFFFF; /* Reset LFN sequence */
+#endif
+ do {
+ res = move_window(dp->fs, dp->sect);
+ if (res != FR_OK) break;
+ dir = dp->dir; /* Ptr to the directory entry of current index */
+ c = dir[DIR_Name];
+ if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */
+#if _USE_LFN /* LFN configuration */
+ a = dir[DIR_Attr] & AM_MASK;
+ if (c == DDEM || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */
+ ord = 0xFF; dp->lfn_idx = 0xFFFF; /* Reset LFN sequence */
+ } else {
+ if (a == AM_LFN) { /* An LFN entry is found */
+ if (dp->lfn) {
+ if (c & LLEF) { /* Is it start of LFN sequence? */
+ sum = dir[LDIR_Chksum];
+ c &= ~LLEF; ord = c; /* LFN start order */
+ dp->lfn_idx = dp->index; /* Start index of LFN */
+ }
+ /* Check validity of the LFN entry and compare it with given name */
+ ord = (c == ord && sum == dir[LDIR_Chksum] && cmp_lfn(dp->lfn, dir)) ? ord - 1 : 0xFF;
+ }
+ } else { /* An SFN entry is found */
+ if (!ord && sum == sum_sfn(dir)) break; /* LFN matched? */
+ if (!(dp->fn[NSFLAG] & NS_LOSS) && !mem_cmp(dir, dp->fn, 11)) break; /* SFN matched? */
+ ord = 0xFF; dp->lfn_idx = 0xFFFF; /* Reset LFN sequence */
+ }
+ }
+#else /* Non LFN configuration */
+ if (!(dir[DIR_Attr] & AM_VOL) && !mem_cmp(dir, dp->fn, 11)) /* Is it a valid entry? */
+ break;
+#endif
+ res = dir_next(dp, 0); /* Next entry */
+ } while (res == FR_OK);
+
+ return res;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Read an object from the directory */
+/*-----------------------------------------------------------------------*/
+#if _FS_MINIMIZE <= 1 || _USE_LABEL || _FS_RPATH >= 2
+static
+FRESULT dir_read (
+ DIR* dp, /* Pointer to the directory object */
+ int vol /* Filtered by 0:file/directory or 1:volume label */
+)
+{
+ FRESULT res;
+ BYTE a, c, *dir;
+#if _USE_LFN
+ BYTE ord = 0xFF, sum = 0xFF;
+#endif
+
+ res = FR_NO_FILE;
+ while (dp->sect) {
+ res = move_window(dp->fs, dp->sect);
+ if (res != FR_OK) break;
+ dir = dp->dir; /* Ptr to the directory entry of current index */
+ c = dir[DIR_Name];
+ if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */
+ a = dir[DIR_Attr] & AM_MASK;
+#if _USE_LFN /* LFN configuration */
+ if (c == DDEM || (!_FS_RPATH && c == '.') || (int)((a & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */
+ ord = 0xFF;
+ } else {
+ if (a == AM_LFN) { /* An LFN entry is found */
+ if (c & LLEF) { /* Is it start of LFN sequence? */
+ sum = dir[LDIR_Chksum];
+ c &= ~LLEF; ord = c;
+ dp->lfn_idx = dp->index;
+ }
+ /* Check LFN validity and capture it */
+ ord = (c == ord && sum == dir[LDIR_Chksum] && pick_lfn(dp->lfn, dir)) ? ord - 1 : 0xFF;
+ } else { /* An SFN entry is found */
+ if (ord || sum != sum_sfn(dir)) /* Is there a valid LFN? */
+ dp->lfn_idx = 0xFFFF; /* It has no LFN. */
+ break;
+ }
+ }
+#else /* Non LFN configuration */
+ if (c != DDEM && (_FS_RPATH || c != '.') && a != AM_LFN && (int)((a & ~AM_ARC) == AM_VOL) == vol) /* Is it a valid entry? */
+ break;
+#endif
+ res = dir_next(dp, 0); /* Next entry */
+ if (res != FR_OK) break;
+ }
+
+ if (res != FR_OK) dp->sect = 0;
+
+ return res;
+}
+#endif /* _FS_MINIMIZE <= 1 || _USE_LABEL || _FS_RPATH >= 2 */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Register an object to the directory */
+/*-----------------------------------------------------------------------*/
+#if !_FS_READONLY
+static
+FRESULT dir_register ( /* FR_OK:Successful, FR_DENIED:No free entry or too many SFN collision, FR_DISK_ERR:Disk error */
+ DIR* dp /* Target directory with object name to be created */
+)
+{
+ FRESULT res;
+#if _USE_LFN /* LFN configuration */
+ UINT n, nent;
+ BYTE sn[12], *fn, sum;
+ WCHAR *lfn;
+
+
+ fn = dp->fn; lfn = dp->lfn;
+ mem_cpy(sn, fn, 12);
+
+ if (_FS_RPATH && (sn[NSFLAG] & NS_DOT)) /* Cannot create dot entry */
+ return FR_INVALID_NAME;
+
+ if (sn[NSFLAG] & NS_LOSS) { /* When LFN is out of 8.3 format, generate a numbered name */
+ fn[NSFLAG] = 0; dp->lfn = 0; /* Find only SFN */
+ for (n = 1; n < 100; n++) {
+ gen_numname(fn, sn, lfn, n); /* Generate a numbered name */
+ res = dir_find(dp); /* Check if the name collides with existing SFN */
+ if (res != FR_OK) break;
+ }
+ if (n == 100) return FR_DENIED; /* Abort if too many collisions */
+ if (res != FR_NO_FILE) return res; /* Abort if the result is other than 'not collided' */
+ fn[NSFLAG] = sn[NSFLAG]; dp->lfn = lfn;
+ }
+
+ if (sn[NSFLAG] & NS_LFN) { /* When LFN is to be created, allocate entries for an SFN + LFNs. */
+ for (n = 0; lfn[n]; n++) ;
+ nent = (n + 25) / 13;
+ } else { /* Otherwise allocate an entry for an SFN */
+ nent = 1;
+ }
+ res = dir_alloc(dp, nent); /* Allocate entries */
+
+ if (res == FR_OK && --nent) { /* Set LFN entry if needed */
+ res = dir_sdi(dp, dp->index - nent);
+ if (res == FR_OK) {
+ sum = sum_sfn(dp->fn); /* Sum value of the SFN tied to the LFN */
+ do { /* Store LFN entries in bottom first */
+ res = move_window(dp->fs, dp->sect);
+ if (res != FR_OK) break;
+ fit_lfn(dp->lfn, dp->dir, (BYTE)nent, sum);
+ dp->fs->wflag = 1;
+ res = dir_next(dp, 0); /* Next entry */
+ } while (res == FR_OK && --nent);
+ }
+ }
+#else /* Non LFN configuration */
+ res = dir_alloc(dp, 1); /* Allocate an entry for SFN */
+#endif
+
+ if (res == FR_OK) { /* Set SFN entry */
+ res = move_window(dp->fs, dp->sect);
+ if (res == FR_OK) {
+ mem_set(dp->dir, 0, SZ_DIRE); /* Clean the entry */
+ mem_cpy(dp->dir, dp->fn, 11); /* Put SFN */
+#if _USE_LFN
+ dp->dir[DIR_NTres] = dp->fn[NSFLAG] & (NS_BODY | NS_EXT); /* Put NT flag */
+#endif
+ dp->fs->wflag = 1;
+ }
+ }
+
+ return res;
+}
+#endif /* !_FS_READONLY */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Remove an object from the directory */
+/*-----------------------------------------------------------------------*/
+#if !_FS_READONLY && !_FS_MINIMIZE
+static
+FRESULT dir_remove ( /* FR_OK: Successful, FR_DISK_ERR: A disk error */
+ DIR* dp /* Directory object pointing the entry to be removed */
+)
+{
+ FRESULT res;
+#if _USE_LFN /* LFN configuration */
+ UINT i;
+
+ i = dp->index; /* SFN index */
+ res = dir_sdi(dp, (dp->lfn_idx == 0xFFFF) ? i : dp->lfn_idx); /* Goto the SFN or top of the LFN entries */
+ if (res == FR_OK) {
+ do {
+ res = move_window(dp->fs, dp->sect);
+ if (res != FR_OK) break;
+ mem_set(dp->dir, 0, SZ_DIRE); /* Clear and mark the entry "deleted" */
+ *dp->dir = DDEM;
+ dp->fs->wflag = 1;
+ if (dp->index >= i) break; /* When reached SFN, all entries of the object has been deleted. */
+ res = dir_next(dp, 0); /* Next entry */
+ } while (res == FR_OK);
+ if (res == FR_NO_FILE) res = FR_INT_ERR;
+ }
+
+#else /* Non LFN configuration */
+ res = dir_sdi(dp, dp->index);
+ if (res == FR_OK) {
+ res = move_window(dp->fs, dp->sect);
+ if (res == FR_OK) {
+ mem_set(dp->dir, 0, SZ_DIRE); /* Clear and mark the entry "deleted" */
+ *dp->dir = DDEM;
+ dp->fs->wflag = 1;
+ }
+ }
+#endif
+
+ return res;
+}
+#endif /* !_FS_READONLY */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Get file information from directory entry */
+/*-----------------------------------------------------------------------*/
+#if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2
+static
+void get_fileinfo ( /* No return code */
+ DIR* dp, /* Pointer to the directory object */
+ FILINFO* fno /* Pointer to the file information to be filled */
+)
+{
+ UINT i;
+ TCHAR *p, c;
+ BYTE *dir;
+#if _USE_LFN
+ WCHAR w, *lfn;
+#endif
+
+ p = fno->fname;
+ if (dp->sect) { /* Get SFN */
+ dir = dp->dir;
+ i = 0;
+ while (i < 11) { /* Copy name body and extension */
+ c = (TCHAR)dir[i++];
+ if (c == ' ') continue; /* Skip padding spaces */
+ if (c == RDDEM) c = (TCHAR)DDEM; /* Restore replaced DDEM character */
+ if (i == 9) *p++ = '.'; /* Insert a . if extension is exist */
+#if _USE_LFN
+ if (IsUpper(c) && (dir[DIR_NTres] & (i >= 9 ? NS_EXT : NS_BODY)))
+ c += 0x20; /* To lower */
+#if _LFN_UNICODE
+ if (IsDBCS1(c) && i != 8 && i != 11 && IsDBCS2(dir[i]))
+ c = c << 8 | dir[i++];
+ c = ff_convert(c, 1); /* OEM -> Unicode */
+ if (!c) c = '?';
+#endif
+#endif
+ *p++ = c;
+ }
+ fno->fattrib = dir[DIR_Attr]; /* Attribute */
+ fno->fsize = LD_DWORD(dir + DIR_FileSize); /* Size */
+ fno->fdate = LD_WORD(dir + DIR_WrtDate); /* Date */
+ fno->ftime = LD_WORD(dir + DIR_WrtTime); /* Time */
+ }
+ *p = 0; /* Terminate SFN string by a \0 */
+
+#if _USE_LFN
+ if (fno->lfname) {
+ i = 0; p = fno->lfname;
+ if (dp->sect && fno->lfsize && dp->lfn_idx != 0xFFFF) { /* Get LFN if available */
+ lfn = dp->lfn;
+ while ((w = *lfn++) != 0) { /* Get an LFN character */
+#if !_LFN_UNICODE
+ w = ff_convert(w, 0); /* Unicode -> OEM */
+ if (!w) { i = 0; break; } /* No LFN if it could not be converted */
+ if (_DF1S && w >= 0x100) /* Put 1st byte if it is a DBC (always false on SBCS cfg) */
+ p[i++] = (TCHAR)(w >> 8);
+#endif
+ if (i >= fno->lfsize - 1) { i = 0; break; } /* No LFN if buffer overflow */
+ p[i++] = (TCHAR)w;
+ }
+ }
+ p[i] = 0; /* Terminate LFN string by a \0 */
+ }
+#endif
+}
+#endif /* _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Pattern matching */
+/*-----------------------------------------------------------------------*/
+#if _USE_FIND && _FS_MINIMIZE <= 1
+static
+WCHAR get_achar ( /* Get a character and advances ptr 1 or 2 */
+ const TCHAR** ptr /* Pointer to pointer to the SBCS/DBCS/Unicode string */
+)
+{
+ WCHAR chr;
+
+#if !_LFN_UNICODE
+ chr = (BYTE)*(*ptr)++; /* Get a byte */
+ if (IsLower(chr)) chr -= 0x20; /* To upper ASCII char */
+ if (IsDBCS1(chr) && IsDBCS2(**ptr)) /* Get DBC 2nd byte if needed */
+ chr = chr << 8 | (BYTE)*(*ptr)++;
+#ifdef _EXCVT
+ if (chr >= 0x80) chr = ExCvt[chr - 0x80]; /* To upper SBCS extended char */
+#endif
+#else
+ chr = ff_wtoupper(*(*ptr)++); /* Get a word and to upper */
+#endif
+ return chr;
+}
+
+
+static
+int pattern_matching ( /* Return value: 0:mismatched, 1:matched */
+ const TCHAR* pat, /* Matching pattern */
+ const TCHAR* nam, /* String to be tested */
+ int skip, /* Number of pre-skip chars (number of ?s) */
+ int inf /* Infinite search (* specified) */
+)
+{
+ const TCHAR *pp, *np;
+ WCHAR pc, nc;
+ int nm, nx;
+
+
+ while (skip--) { /* Pre-skip name chars */
+ if (!get_achar(&nam)) return 0; /* Branch mismatched if less name chars */
+ }
+ if (!*pat && inf) return 1; /* (short circuit) */
+
+ do {
+ pp = pat; np = nam; /* Top of pattern and name to match */
+ for (;;) {
+ if (*pp == '?' || *pp == '*') { /* Wildcard? */
+ nm = nx = 0;
+ do { /* Analyze the wildcard chars */
+ if (*pp++ == '?') nm++; else nx = 1;
+ } while (*pp == '?' || *pp == '*');
+ if (pattern_matching(pp, np, nm, nx)) return 1; /* Test new branch (recurs upto number of wildcard blocks in the pattern) */
+ nc = *np; break; /* Branch mismatched */
+ }
+ pc = get_achar(&pp); /* Get a pattern char */
+ nc = get_achar(&np); /* Get a name char */
+ if (pc != nc) break; /* Branch mismatched? */
+ if (!pc) return 1; /* Branch matched? (matched at end of both strings) */
+ }
+ get_achar(&nam); /* nam++ */
+ } while (inf && nc); /* Retry until end of name if infinite search is specified */
+
+ return 0;
+}
+#endif /* _USE_FIND && _FS_MINIMIZE <= 1 */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Pick a segment and create the object name in directory form */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT create_name (
+ DIR* dp, /* Pointer to the directory object */
+ const TCHAR** path /* Pointer to pointer to the segment in the path string */
+)
+{
+#if _USE_LFN /* LFN configuration */
+ BYTE b, cf;
+ WCHAR w, *lfn;
+ UINT i, ni, si, di;
+ const TCHAR *p;
+
+ /* Create LFN in Unicode */
+ for (p = *path; *p == '/' || *p == '\\'; p++) ; /* Strip duplicated separator */
+ lfn = dp->lfn;
+ si = di = 0;
+ for (;;) {
+ w = p[si++]; /* Get a character */
+ if (w < ' ' || w == '/' || w == '\\') break; /* Break on end of segment */
+ if (di >= _MAX_LFN) /* Reject too long name */
+ return FR_INVALID_NAME;
+#if !_LFN_UNICODE
+ w &= 0xFF;
+ if (IsDBCS1(w)) { /* Check if it is a DBC 1st byte (always false on SBCS cfg) */
+ b = (BYTE)p[si++]; /* Get 2nd byte */
+ w = (w << 8) + b; /* Create a DBC */
+ if (!IsDBCS2(b))
+ return FR_INVALID_NAME; /* Reject invalid sequence */
+ }
+ w = ff_convert(w, 1); /* Convert ANSI/OEM to Unicode */
+ if (!w) return FR_INVALID_NAME; /* Reject invalid code */
+#endif
+ if (w < 0x80 && chk_chr("\"*:<>\?|\x7F", w)) /* Reject illegal characters for LFN */
+ return FR_INVALID_NAME;
+ lfn[di++] = w; /* Store the Unicode character */
+ }
+ *path = &p[si]; /* Return pointer to the next segment */
+ cf = (w < ' ') ? NS_LAST : 0; /* Set last segment flag if end of path */
+#if _FS_RPATH
+ if ((di == 1 && lfn[di - 1] == '.') || /* Is this a dot entry? */
+ (di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) {
+ lfn[di] = 0;
+ for (i = 0; i < 11; i++)
+ dp->fn[i] = (i < di) ? '.' : ' ';
+ dp->fn[i] = cf | NS_DOT; /* This is a dot entry */
+ return FR_OK;
+ }
+#endif
+ while (di) { /* Strip trailing spaces and dots */
+ w = lfn[di - 1];
+ if (w != ' ' && w != '.') break;
+ di--;
+ }
+ if (!di) return FR_INVALID_NAME; /* Reject nul string */
+
+ lfn[di] = 0; /* LFN is created */
+
+ /* Create SFN in directory form */
+ mem_set(dp->fn, ' ', 11);
+ for (si = 0; lfn[si] == ' ' || lfn[si] == '.'; si++) ; /* Strip leading spaces and dots */
+ if (si) cf |= NS_LOSS | NS_LFN;
+ while (di && lfn[di - 1] != '.') di--; /* Find extension (di<=si: no extension) */
+
+ b = i = 0; ni = 8;
+ for (;;) {
+ w = lfn[si++]; /* Get an LFN character */
+ if (!w) break; /* Break on end of the LFN */
+ if (w == ' ' || (w == '.' && si != di)) { /* Remove spaces and dots */
+ cf |= NS_LOSS | NS_LFN; continue;
+ }
+
+ if (i >= ni || si == di) { /* Extension or end of SFN */
+ if (ni == 11) { /* Long extension */
+ cf |= NS_LOSS | NS_LFN; break;
+ }
+ if (si != di) cf |= NS_LOSS | NS_LFN; /* Out of 8.3 format */
+ if (si > di) break; /* No extension */
+ si = di; i = 8; ni = 11; /* Enter extension section */
+ b <<= 2; continue;
+ }
+
+ if (w >= 0x80) { /* Non ASCII character */
+#ifdef _EXCVT
+ w = ff_convert(w, 0); /* Unicode -> OEM code */
+ if (w) w = ExCvt[w - 0x80]; /* Convert extended character to upper (SBCS) */
+#else
+ w = ff_convert(ff_wtoupper(w), 0); /* Upper converted Unicode -> OEM code */
+#endif
+ cf |= NS_LFN; /* Force create LFN entry */
+ }
+
+ if (_DF1S && w >= 0x100) { /* DBC (always false at SBCS cfg) */
+ if (i >= ni - 1) {
+ cf |= NS_LOSS | NS_LFN; i = ni; continue;
+ }
+ dp->fn[i++] = (BYTE)(w >> 8);
+ } else { /* SBC */
+ if (!w || chk_chr("+,;=[]", w)) { /* Replace illegal characters for SFN */
+ w = '_'; cf |= NS_LOSS | NS_LFN;/* Lossy conversion */
+ } else {
+ if (IsUpper(w)) { /* ASCII large capital */
+ b |= 2;
+ } else {
+ if (IsLower(w)) { /* ASCII small capital */
+ b |= 1; w -= 0x20;
+ }
+ }
+ }
+ }
+ dp->fn[i++] = (BYTE)w;
+ }
+
+ if (dp->fn[0] == DDEM) dp->fn[0] = RDDEM; /* If the first character collides with deleted mark, replace it with RDDEM */
+
+ if (ni == 8) b <<= 2;
+ if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03) /* Create LFN entry when there are composite capitals */
+ cf |= NS_LFN;
+ if (!(cf & NS_LFN)) { /* When LFN is in 8.3 format without extended character, NT flags are created */
+ if ((b & 0x03) == 0x01) cf |= NS_EXT; /* NT flag (Extension has only small capital) */
+ if ((b & 0x0C) == 0x04) cf |= NS_BODY; /* NT flag (Filename has only small capital) */
+ }
+
+ dp->fn[NSFLAG] = cf; /* SFN is created */
+
+ return FR_OK;
+
+
+#else /* Non-LFN configuration */
+ BYTE b, c, d, *sfn;
+ UINT ni, si, i;
+ const char *p;
+
+ /* Create file name in directory form */
+ for (p = *path; *p == '/' || *p == '\\'; p++) ; /* Strip duplicated separator */
+ sfn = dp->fn;
+ mem_set(sfn, ' ', 11);
+ si = i = b = 0; ni = 8;
+#if _FS_RPATH
+ if (p[si] == '.') { /* Is this a dot entry? */
+ for (;;) {
+ c = (BYTE)p[si++];
+ if (c != '.' || si >= 3) break;
+ sfn[i++] = c;
+ }
+ if (c != '/' && c != '\\' && c > ' ') return FR_INVALID_NAME;
+ *path = &p[si]; /* Return pointer to the next segment */
+ sfn[NSFLAG] = (c <= ' ') ? NS_LAST | NS_DOT : NS_DOT; /* Set last segment flag if end of path */
+ return FR_OK;
+ }
+#endif
+ for (;;) {
+ c = (BYTE)p[si++];
+ if (c <= ' ' || c == '/' || c == '\\') break; /* Break on end of segment */
+ if (c == '.' || i >= ni) {
+ if (ni != 8 || c != '.') return FR_INVALID_NAME;
+ i = 8; ni = 11;
+ b <<= 2; continue;
+ }
+ if (c >= 0x80) { /* Extended character? */
+ b |= 3; /* Eliminate NT flag */
+#ifdef _EXCVT
+ c = ExCvt[c - 0x80]; /* To upper extended characters (SBCS cfg) */
+#else
+#if !_DF1S
+ return FR_INVALID_NAME; /* Reject extended characters (ASCII cfg) */
+#endif
+#endif
+ }
+ if (IsDBCS1(c)) { /* Check if it is a DBC 1st byte (always false on SBCS cfg) */
+ d = (BYTE)p[si++]; /* Get 2nd byte */
+ if (!IsDBCS2(d) || i >= ni - 1) /* Reject invalid DBC */
+ return FR_INVALID_NAME;
+ sfn[i++] = c;
+ sfn[i++] = d;
+ } else { /* SBC */
+ if (chk_chr("\"*+,:;<=>\?[]|\x7F", c)) /* Reject illegal chrs for SFN */
+ return FR_INVALID_NAME;
+ if (IsUpper(c)) { /* ASCII large capital? */
+ b |= 2;
+ } else {
+ if (IsLower(c)) { /* ASCII small capital? */
+ b |= 1; c -= 0x20;
+ }
+ }
+ sfn[i++] = c;
+ }
+ }
+ *path = &p[si]; /* Return pointer to the next segment */
+ c = (c <= ' ') ? NS_LAST : 0; /* Set last segment flag if end of path */
+
+ if (!i) return FR_INVALID_NAME; /* Reject nul string */
+ if (sfn[0] == DDEM) sfn[0] = RDDEM; /* When first character collides with DDEM, replace it with RDDEM */
+
+ if (ni == 8) b <<= 2;
+ if ((b & 0x03) == 0x01) c |= NS_EXT; /* NT flag (Name extension has only small capital) */
+ if ((b & 0x0C) == 0x04) c |= NS_BODY; /* NT flag (Name body has only small capital) */
+
+ sfn[NSFLAG] = c; /* Store NT flag, File name is created */
+
+ return FR_OK;
+#endif
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Follow a file path */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */
+ DIR* dp, /* Directory object to return last directory and found object */
+ const TCHAR* path /* Full-path string to find a file or directory */
+)
+{
+ FRESULT res;
+ BYTE *dir, ns;
+
+
+#if _FS_RPATH
+ if (*path == '/' || *path == '\\') { /* There is a heading separator */
+ path++; dp->sclust = 0; /* Strip it and start from the root directory */
+ } else { /* No heading separator */
+ dp->sclust = dp->fs->cdir; /* Start from the current directory */
+ }
+#else
+ if (*path == '/' || *path == '\\') /* Strip heading separator if exist */
+ path++;
+ dp->sclust = 0; /* Always start from the root directory */
+#endif
+
+ if ((UINT)*path < ' ') { /* Null path name is the origin directory itself */
+ res = dir_sdi(dp, 0);
+ dp->dir = 0;
+ } else { /* Follow path */
+ for (;;) {
+ res = create_name(dp, &path); /* Get a segment name of the path */
+ if (res != FR_OK) break;
+ res = dir_find(dp); /* Find an object with the sagment name */
+ ns = dp->fn[NSFLAG];
+ if (res != FR_OK) { /* Failed to find the object */
+ if (res == FR_NO_FILE) { /* Object is not found */
+ if (_FS_RPATH && (ns & NS_DOT)) { /* If dot entry is not exist, */
+ dp->sclust = 0; dp->dir = 0; /* it is the root directory and stay there */
+ if (!(ns & NS_LAST)) continue; /* Continue to follow if not last segment */
+ res = FR_OK; /* Ended at the root directroy. Function completed. */
+ } else { /* Could not find the object */
+ if (!(ns & NS_LAST)) res = FR_NO_PATH; /* Adjust error code if not last segment */
+ }
+ }
+ break;
+ }
+ if (ns & NS_LAST) break; /* Last segment matched. Function completed. */
+ dir = dp->dir; /* Follow the sub-directory */
+ if (!(dir[DIR_Attr] & AM_DIR)) { /* It is not a sub-directory and cannot follow */
+ res = FR_NO_PATH; break;
+ }
+ dp->sclust = ld_clust(dp->fs, dir);
+ }
+ }
+
+ return res;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Get logical drive number from path name */
+/*-----------------------------------------------------------------------*/
+
+static
+int get_ldnumber ( /* Returns logical drive number (-1:invalid drive) */
+ const TCHAR** path /* Pointer to pointer to the path name */
+)
+{
+ const TCHAR *tp, *tt;
+ UINT i;
+ int vol = -1;
+#if _STR_VOLUME_ID /* Find string drive id */
+ static const char* const str[] = {_VOLUME_STRS};
+ const char *sp;
+ char c;
+ TCHAR tc;
+#endif
+
+
+ if (*path) { /* If the pointer is not a null */
+ for (tt = *path; (UINT)*tt >= (_USE_LFN ? ' ' : '!') && *tt != ':'; tt++) ; /* Find ':' in the path */
+ if (*tt == ':') { /* If a ':' is exist in the path name */
+ tp = *path;
+ i = *tp++ - '0';
+ if (i < 10 && tp == tt) { /* Is there a numeric drive id? */
+ if (i < _VOLUMES) { /* If a drive id is found, get the value and strip it */
+ vol = (int)i;
+ *path = ++tt;
+ }
+ }
+#if _STR_VOLUME_ID
+ else { /* No numeric drive number, find string drive id */
+ i = 0; tt++;
+ do {
+ sp = str[i]; tp = *path;
+ do { /* Compare a string drive id with path name */
+ c = *sp++; tc = *tp++;
+ if (IsLower(tc)) tc -= 0x20;
+ } while (c && (TCHAR)c == tc);
+ } while ((c || tp != tt) && ++i < _VOLUMES); /* Repeat for each id until pattern match */
+ if (i < _VOLUMES) { /* If a drive id is found, get the value and strip it */
+ vol = (int)i;
+ *path = tt;
+ }
+ }
+#endif
+ return vol;
+ }
+#if _FS_RPATH && _VOLUMES >= 2
+ vol = CurrVol; /* Current drive */
+#else
+ vol = 0; /* Drive 0 */
+#endif
+ }
+ return vol;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Load a sector and check if it is an FAT boot sector */
+/*-----------------------------------------------------------------------*/
+
+static
+BYTE check_fs ( /* 0:FAT boor sector, 1:Valid boor sector but not FAT, 2:Not a boot sector, 3:Disk error */
+ FATFS* fs, /* File system object */
+ DWORD sect /* Sector# (lba) to check if it is an FAT boot record or not */
+)
+{
+ fs->wflag = 0; fs->winsect = 0xFFFFFFFF; /* Invaidate window */
+ if (move_window(fs, sect) != FR_OK) /* Load boot record */
+ return 3;
+
+ if (LD_WORD(&fs->win[BS_55AA]) != 0xAA55) /* Check boot record signature (always placed at offset 510 even if the sector size is >512) */
+ return 2;
+
+ if ((LD_DWORD(&fs->win[BS_FilSysType]) & 0xFFFFFF) == 0x544146) /* Check "FAT" string */
+ return 0;
+ if ((LD_DWORD(&fs->win[BS_FilSysType32]) & 0xFFFFFF) == 0x544146) /* Check "FAT" string */
+ return 0;
+
+ return 1;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Find logical drive and check if the volume is mounted */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */
+ FATFS** rfs, /* Pointer to pointer to the found file system object */
+ const TCHAR** path, /* Pointer to pointer to the path name (drive number) */
+ BYTE wmode /* !=0: Check write protection for write access */
+)
+{
+ BYTE fmt, *pt;
+ int vol;
+ DSTATUS stat;
+ DWORD bsect, fasize, tsect, sysect, nclst, szbfat, br[4];
+ WORD nrsv;
+ FATFS *fs;
+ UINT i;
+
+
+ /* Get logical drive number from the path name */
+ *rfs = 0;
+ vol = get_ldnumber(path);
+ if (vol < 0) return FR_INVALID_DRIVE;
+
+ /* Check if the file system object is valid or not */
+ fs = FatFs[vol]; /* Get pointer to the file system object */
+ if (!fs) return FR_NOT_ENABLED; /* Is the file system object available? */
+
+ ENTER_FF(fs); /* Lock the volume */
+ *rfs = fs; /* Return pointer to the file system object */
+
+ if (fs->fs_type) { /* If the volume has been mounted */
+ stat = disk_status(fs->drv);
+ if (!(stat & STA_NOINIT)) { /* and the physical drive is kept initialized */
+ if (!_FS_READONLY && wmode && (stat & STA_PROTECT)) /* Check write protection if needed */
+ return FR_WRITE_PROTECTED;
+ return FR_OK; /* The file system object is valid */
+ }
+ }
+
+ /* The file system object is not valid. */
+ /* Following code attempts to mount the volume. (analyze BPB and initialize the fs object) */
+
+ fs->fs_type = 0; /* Clear the file system object */
+ fs->drv = LD2PD(vol); /* Bind the logical drive and a physical drive */
+ stat = disk_initialize(fs->drv); /* Initialize the physical drive */
+ if (stat & STA_NOINIT) /* Check if the initialization succeeded */
+ return FR_NOT_READY; /* Failed to initialize due to no medium or hard error */
+ if (!_FS_READONLY && wmode && (stat & STA_PROTECT)) /* Check disk write protection if needed */
+ return FR_WRITE_PROTECTED;
+#if _MAX_SS != _MIN_SS /* Get sector size (multiple sector size cfg only) */
+ if (disk_ioctl(fs->drv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK
+ || SS(fs) < _MIN_SS || SS(fs) > _MAX_SS) return FR_DISK_ERR;
+#endif
+ /* Find an FAT partition on the drive. Supports only generic partitioning, FDISK and SFD. */
+ bsect = 0;
+ fmt = check_fs(fs, bsect); /* Load sector 0 and check if it is an FAT boot sector as SFD */
+ if (fmt == 1 || (!fmt && (LD2PT(vol)))) { /* Not an FAT boot sector or forced partition number */
+ for (i = 0; i < 4; i++) { /* Get partition offset */
+ pt = fs->win + MBR_Table + i * SZ_PTE;
+ br[i] = pt[4] ? LD_DWORD(&pt[8]) : 0;
+ }
+ i = LD2PT(vol); /* Partition number: 0:auto, 1-4:forced */
+ if (i) i--;
+ do { /* Find an FAT volume */
+ bsect = br[i];
+ fmt = bsect ? check_fs(fs, bsect) : 2; /* Check the partition */
+ } while (!LD2PT(vol) && fmt && ++i < 4);
+ }
+ if (fmt == 3) return FR_DISK_ERR; /* An error occured in the disk I/O layer */
+ if (fmt) return FR_NO_FILESYSTEM; /* No FAT volume is found */
+
+ /* An FAT volume is found. Following code initializes the file system object */
+
+ if (LD_WORD(fs->win + BPB_BytsPerSec) != SS(fs)) /* (BPB_BytsPerSec must be equal to the physical sector size) */
+ return FR_NO_FILESYSTEM;
+
+ fasize = LD_WORD(fs->win + BPB_FATSz16); /* Number of sectors per FAT */
+ if (!fasize) fasize = LD_DWORD(fs->win + BPB_FATSz32);
+ fs->fsize = fasize;
+
+ fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FAT copies */
+ if (fs->n_fats != 1 && fs->n_fats != 2) /* (Must be 1 or 2) */
+ return FR_NO_FILESYSTEM;
+ fasize *= fs->n_fats; /* Number of sectors for FAT area */
+
+ fs->csize = fs->win[BPB_SecPerClus]; /* Number of sectors per cluster */
+ if (!fs->csize || (fs->csize & (fs->csize - 1))) /* (Must be power of 2) */
+ return FR_NO_FILESYSTEM;
+
+ fs->n_rootdir = LD_WORD(fs->win + BPB_RootEntCnt); /* Number of root directory entries */
+ if (fs->n_rootdir % (SS(fs) / SZ_DIRE)) /* (Must be sector aligned) */
+ return FR_NO_FILESYSTEM;
+
+ tsect = LD_WORD(fs->win + BPB_TotSec16); /* Number of sectors on the volume */
+ if (!tsect) tsect = LD_DWORD(fs->win + BPB_TotSec32);
+
+ nrsv = LD_WORD(fs->win + BPB_RsvdSecCnt); /* Number of reserved sectors */
+ if (!nrsv) return FR_NO_FILESYSTEM; /* (Must not be 0) */
+
+ /* Determine the FAT sub type */
+ sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZ_DIRE); /* RSV + FAT + DIR */
+ if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */
+ nclst = (tsect - sysect) / fs->csize; /* Number of clusters */
+ if (!nclst) return FR_NO_FILESYSTEM; /* (Invalid volume size) */
+ fmt = FS_FAT12;
+ if (nclst >= MIN_FAT16) fmt = FS_FAT16;
+ if (nclst >= MIN_FAT32) fmt = FS_FAT32;
+
+ /* Boundaries and Limits */
+ fs->n_fatent = nclst + 2; /* Number of FAT entries */
+ fs->volbase = bsect; /* Volume start sector */
+ fs->fatbase = bsect + nrsv; /* FAT start sector */
+ fs->database = bsect + sysect; /* Data start sector */
+ if (fmt == FS_FAT32) {
+ if (fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */
+ fs->dirbase = LD_DWORD(fs->win + BPB_RootClus); /* Root directory start cluster */
+ szbfat = fs->n_fatent * 4; /* (Needed FAT size) */
+ } else {
+ if (!fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must not be 0) */
+ fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */
+ szbfat = (fmt == FS_FAT16) ? /* (Needed FAT size) */
+ fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1);
+ }
+ if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) /* (BPB_FATSz must not be less than the size needed) */
+ return FR_NO_FILESYSTEM;
+
+#if !_FS_READONLY
+ /* Initialize cluster allocation information */
+ fs->last_clust = fs->free_clust = 0xFFFFFFFF;
+
+ /* Get fsinfo if available */
+ fs->fsi_flag = 0x80;
+#if (_FS_NOFSINFO & 3) != 3
+ if (fmt == FS_FAT32 /* Enable FSINFO only if FAT32 and BPB_FSInfo is 1 */
+ && LD_WORD(fs->win + BPB_FSInfo) == 1
+ && move_window(fs, bsect + 1) == FR_OK)
+ {
+ fs->fsi_flag = 0;
+ if (LD_WORD(fs->win + BS_55AA) == 0xAA55 /* Load FSINFO data if available */
+ && LD_DWORD(fs->win + FSI_LeadSig) == 0x41615252
+ && LD_DWORD(fs->win + FSI_StrucSig) == 0x61417272)
+ {
+#if (_FS_NOFSINFO & 1) == 0
+ fs->free_clust = LD_DWORD(fs->win + FSI_Free_Count);
+#endif
+#if (_FS_NOFSINFO & 2) == 0
+ fs->last_clust = LD_DWORD(fs->win + FSI_Nxt_Free);
+#endif
+ }
+ }
+#endif
+#endif
+ fs->fs_type = fmt; /* FAT sub-type */
+ fs->id = ++Fsid; /* File system mount ID */
+#if _FS_RPATH
+ fs->cdir = 0; /* Set current directory to root */
+#endif
+#if _FS_LOCK /* Clear file lock semaphores */
+ clear_lock(fs);
+#endif
+
+ return FR_OK;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Check if the file/directory object is valid or not */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT validate ( /* FR_OK(0): The object is valid, !=0: Invalid */
+ void* obj /* Pointer to the object FIL/DIR to check validity */
+)
+{
+ FIL *fil = (FIL*)obj; /* Assuming offset of .fs and .id in the FIL/DIR structure is identical */
+
+
+ if (!fil || !fil->fs || !fil->fs->fs_type || fil->fs->id != fil->id)
+ return FR_INVALID_OBJECT;
+
+ ENTER_FF(fil->fs); /* Lock file system */
+
+ if (disk_status(fil->fs->drv) & STA_NOINIT)
+ return FR_NOT_READY;
+
+ return FR_OK;
+}
+
+
+
+
+/*--------------------------------------------------------------------------
+
+ Public Functions
+
+--------------------------------------------------------------------------*/
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Mount/Unmount a Logical Drive */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_mount (
+ FATFS* fs, /* Pointer to the file system object (NULL:unmount)*/
+ const TCHAR* path, /* Logical drive number to be mounted/unmounted */
+ BYTE opt /* 0:Do not mount (delayed mount), 1:Mount immediately */
+)
+{
+ FATFS *cfs;
+ int vol;
+ FRESULT res;
+ const TCHAR *rp = path;
+
+
+ vol = get_ldnumber(&rp);
+ if (vol < 0) return FR_INVALID_DRIVE;
+ cfs = FatFs[vol]; /* Pointer to fs object */
+
+ if (cfs) {
+#if _FS_LOCK
+ clear_lock(cfs);
+#endif
+#if _FS_REENTRANT /* Discard sync object of the current volume */
+ if (!ff_del_syncobj(cfs->sobj)) return FR_INT_ERR;
+#endif
+ cfs->fs_type = 0; /* Clear old fs object */
+ }
+
+ if (fs) {
+ fs->fs_type = 0; /* Clear new fs object */
+#if _FS_REENTRANT /* Create sync object for the new volume */
+ if (!ff_cre_syncobj((BYTE)vol, &fs->sobj)) return FR_INT_ERR;
+#endif
+ }
+ FatFs[vol] = fs; /* Register new fs object */
+
+ if (!fs || opt != 1) return FR_OK; /* Do not mount now, it will be mounted later */
+
+ res = find_volume(&fs, &path, 0); /* Force mounted the volume */
+ LEAVE_FF(fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Open or Create a File */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_open (
+ FIL* fp, /* Pointer to the blank file object */
+ const TCHAR* path, /* Pointer to the file name */
+ BYTE mode /* Access mode and file open mode flags */
+)
+{
+ FRESULT res;
+ DIR dj;
+ BYTE *dir;
+ DEFINE_NAMEBUF;
+#if !_FS_READONLY
+ DWORD dw, cl;
+#endif
+
+
+ if (!fp) return FR_INVALID_OBJECT;
+ fp->fs = 0; /* Clear file object */
+
+ /* Get logical drive number */
+#if !_FS_READONLY
+ mode &= FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW;
+ res = find_volume(&dj.fs, &path, (BYTE)(mode & ~FA_READ));
+#else
+ mode &= FA_READ;
+ res = find_volume(&dj.fs, &path, 0);
+#endif
+ if (res == FR_OK) {
+ INIT_BUF(dj);
+ res = follow_path(&dj, path); /* Follow the file path */
+ dir = dj.dir;
+#if !_FS_READONLY /* R/W configuration */
+ if (res == FR_OK) {
+ if (!dir) /* Default directory itself */
+ res = FR_INVALID_NAME;
+#if _FS_LOCK
+ else
+ res = chk_lock(&dj, (mode & ~FA_READ) ? 1 : 0);
+#endif
+ }
+ /* Create or Open a file */
+ if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) {
+ if (res != FR_OK) { /* No file, create new */
+ if (res == FR_NO_FILE) /* There is no file to open, create a new entry */
+#if _FS_LOCK
+ res = enq_lock() ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES;
+#else
+ res = dir_register(&dj);
+#endif
+ mode |= FA_CREATE_ALWAYS; /* File is created */
+ dir = dj.dir; /* New entry */
+ }
+ else { /* Any object is already existing */
+ if (dir[DIR_Attr] & (AM_RDO | AM_DIR)) { /* Cannot overwrite it (R/O or DIR) */
+ res = FR_DENIED;
+ } else {
+ if (mode & FA_CREATE_NEW) /* Cannot create as new file */
+ res = FR_EXIST;
+ }
+ }
+ if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) { /* Truncate it if overwrite mode */
+ dw = GET_FATTIME(); /* Created time */
+ ST_DWORD(dir + DIR_CrtTime, dw);
+ dir[DIR_Attr] = 0; /* Reset attribute */
+ ST_DWORD(dir + DIR_FileSize, 0);/* size = 0 */
+ cl = ld_clust(dj.fs, dir); /* Get start cluster */
+ st_clust(dir, 0); /* cluster = 0 */
+ dj.fs->wflag = 1;
+ if (cl) { /* Remove the cluster chain if exist */
+ dw = dj.fs->winsect;
+ res = remove_chain(dj.fs, cl);
+ if (res == FR_OK) {
+ dj.fs->last_clust = cl - 1; /* Reuse the cluster hole */
+ res = move_window(dj.fs, dw);
+ }
+ }
+ }
+ }
+ else { /* Open an existing file */
+ if (res == FR_OK) { /* Follow succeeded */
+ if (dir[DIR_Attr] & AM_DIR) { /* It is a directory */
+ res = FR_NO_FILE;
+ } else {
+ if ((mode & FA_WRITE) && (dir[DIR_Attr] & AM_RDO)) /* R/O violation */
+ res = FR_DENIED;
+ }
+ }
+ }
+ if (res == FR_OK) {
+ if (mode & FA_CREATE_ALWAYS) /* Set file change flag if created or overwritten */
+ mode |= FA__WRITTEN;
+ fp->dir_sect = dj.fs->winsect; /* Pointer to the directory entry */
+ fp->dir_ptr = dir;
+#if _FS_LOCK
+ fp->lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0);
+ if (!fp->lockid) res = FR_INT_ERR;
+#endif
+ }
+
+#else /* R/O configuration */
+ if (res == FR_OK) { /* Follow succeeded */
+ dir = dj.dir;
+ if (!dir) { /* Current directory itself */
+ res = FR_INVALID_NAME;
+ } else {
+ if (dir[DIR_Attr] & AM_DIR) /* It is a directory */
+ res = FR_NO_FILE;
+ }
+ }
+#endif
+ FREE_BUF();
+
+ if (res == FR_OK) {
+ fp->flag = mode; /* File access mode */
+ fp->err = 0; /* Clear error flag */
+ fp->sclust = ld_clust(dj.fs, dir); /* File start cluster */
+ fp->fsize = LD_DWORD(dir + DIR_FileSize); /* File size */
+ fp->fptr = 0; /* File pointer */
+ fp->dsect = 0;
+#if _USE_FASTSEEK
+ fp->cltbl = 0; /* Normal seek mode */
+#endif
+ fp->fs = dj.fs; /* Validate file object */
+ fp->id = fp->fs->id;
+ }
+ }
+
+ LEAVE_FF(dj.fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Read File */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_read (
+ FIL* fp, /* Pointer to the file object */
+ void* buff, /* Pointer to data buffer */
+ UINT btr, /* Number of bytes to read */
+ UINT* br /* Pointer to number of bytes read */
+)
+{
+ FRESULT res;
+ DWORD clst, sect, remain;
+ UINT rcnt, cc;
+ BYTE csect, *rbuff = (BYTE*)buff;
+
+
+ *br = 0; /* Clear read byte counter */
+
+ res = validate(fp); /* Check validity */
+ if (res != FR_OK) LEAVE_FF(fp->fs, res);
+ if (fp->err) /* Check error */
+ LEAVE_FF(fp->fs, (FRESULT)fp->err);
+ if (!(fp->flag & FA_READ)) /* Check access mode */
+ LEAVE_FF(fp->fs, FR_DENIED);
+ remain = fp->fsize - fp->fptr;
+ if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */
+
+ for ( ; btr; /* Repeat until all data read */
+ rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) {
+ if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */
+ csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */
+ if (!csect) { /* On the cluster boundary? */
+ if (fp->fptr == 0) { /* On the top of the file? */
+ clst = fp->sclust; /* Follow from the origin */
+ } else { /* Middle or end of the file */
+#if _USE_FASTSEEK
+ if (fp->cltbl)
+ clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */
+ else
+#endif
+ clst = get_fat(fp->fs, fp->clust); /* Follow cluster chain on the FAT */
+ }
+ if (clst < 2) ABORT(fp->fs, FR_INT_ERR);
+ if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
+ fp->clust = clst; /* Update current cluster */
+ }
+ sect = clust2sect(fp->fs, fp->clust); /* Get current sector */
+ if (!sect) ABORT(fp->fs, FR_INT_ERR);
+ sect += csect;
+ cc = btr / SS(fp->fs); /* When remaining bytes >= sector size, */
+ if (cc) { /* Read maximum contiguous sectors directly */
+ if (csect + cc > fp->fs->csize) /* Clip at cluster boundary */
+ cc = fp->fs->csize - csect;
+ if (disk_read(fp->fs->drv, rbuff, sect, cc) != RES_OK)
+ ABORT(fp->fs, FR_DISK_ERR);
+#if !_FS_READONLY && _FS_MINIMIZE <= 2 /* Replace one of the read sectors with cached data if it contains a dirty sector */
+#if _FS_TINY
+ if (fp->fs->wflag && fp->fs->winsect - sect < cc)
+ mem_cpy(rbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), fp->fs->win, SS(fp->fs));
+#else
+ if ((fp->flag & FA__DIRTY) && fp->dsect - sect < cc)
+ mem_cpy(rbuff + ((fp->dsect - sect) * SS(fp->fs)), fp->buf, SS(fp->fs));
+#endif
+#endif
+ rcnt = SS(fp->fs) * cc; /* Number of bytes transferred */
+ continue;
+ }
+#if !_FS_TINY
+ if (fp->dsect != sect) { /* Load data sector if not in cache */
+#if !_FS_READONLY
+ if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */
+ if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
+ ABORT(fp->fs, FR_DISK_ERR);
+ fp->flag &= ~FA__DIRTY;
+ }
+#endif
+ if (disk_read(fp->fs->drv, fp->buf, sect, 1) != RES_OK) /* Fill sector cache */
+ ABORT(fp->fs, FR_DISK_ERR);
+ }
+#endif
+ fp->dsect = sect;
+ }
+ rcnt = SS(fp->fs) - ((UINT)fp->fptr % SS(fp->fs)); /* Get partial sector data from sector buffer */
+ if (rcnt > btr) rcnt = btr;
+#if _FS_TINY
+ if (move_window(fp->fs, fp->dsect) != FR_OK) /* Move sector window */
+ ABORT(fp->fs, FR_DISK_ERR);
+ mem_cpy(rbuff, &fp->fs->win[fp->fptr % SS(fp->fs)], rcnt); /* Pick partial sector */
+#else
+ mem_cpy(rbuff, &fp->buf[fp->fptr % SS(fp->fs)], rcnt); /* Pick partial sector */
+#endif
+ }
+
+ LEAVE_FF(fp->fs, FR_OK);
+}
+
+
+
+
+#if !_FS_READONLY
+/*-----------------------------------------------------------------------*/
+/* Write File */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_write (
+ FIL* fp, /* Pointer to the file object */
+ const void *buff, /* Pointer to the data to be written */
+ UINT btw, /* Number of bytes to write */
+ UINT* bw /* Pointer to number of bytes written */
+)
+{
+ FRESULT res;
+ DWORD clst, sect;
+ UINT wcnt, cc;
+ const BYTE *wbuff = (const BYTE*)buff;
+ BYTE csect;
+
+
+ *bw = 0; /* Clear write byte counter */
+
+ res = validate(fp); /* Check validity */
+ if (res != FR_OK) LEAVE_FF(fp->fs, res);
+ if (fp->err) /* Check error */
+ LEAVE_FF(fp->fs, (FRESULT)fp->err);
+ if (!(fp->flag & FA_WRITE)) /* Check access mode */
+ LEAVE_FF(fp->fs, FR_DENIED);
+ if (fp->fptr + btw < fp->fptr) btw = 0; /* File size cannot reach 4GB */
+
+ for ( ; btw; /* Repeat until all data written */
+ wbuff += wcnt, fp->fptr += wcnt, *bw += wcnt, btw -= wcnt) {
+ if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */
+ csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */
+ if (!csect) { /* On the cluster boundary? */
+ if (fp->fptr == 0) { /* On the top of the file? */
+ clst = fp->sclust; /* Follow from the origin */
+ if (clst == 0) /* When no cluster is allocated, */
+ clst = create_chain(fp->fs, 0); /* Create a new cluster chain */
+ } else { /* Middle or end of the file */
+#if _USE_FASTSEEK
+ if (fp->cltbl)
+ clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */
+ else
+#endif
+ clst = create_chain(fp->fs, fp->clust); /* Follow or stretch cluster chain on the FAT */
+ }
+ if (clst == 0) break; /* Could not allocate a new cluster (disk full) */
+ if (clst == 1) ABORT(fp->fs, FR_INT_ERR);
+ if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
+ fp->clust = clst; /* Update current cluster */
+ if (fp->sclust == 0) fp->sclust = clst; /* Set start cluster if the first write */
+ }
+#if _FS_TINY
+ if (fp->fs->winsect == fp->dsect && sync_window(fp->fs)) /* Write-back sector cache */
+ ABORT(fp->fs, FR_DISK_ERR);
+#else
+ if (fp->flag & FA__DIRTY) { /* Write-back sector cache */
+ if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
+ ABORT(fp->fs, FR_DISK_ERR);
+ fp->flag &= ~FA__DIRTY;
+ }
+#endif
+ sect = clust2sect(fp->fs, fp->clust); /* Get current sector */
+ if (!sect) ABORT(fp->fs, FR_INT_ERR);
+ sect += csect;
+ cc = btw / SS(fp->fs); /* When remaining bytes >= sector size, */
+ if (cc) { /* Write maximum contiguous sectors directly */
+ if (csect + cc > fp->fs->csize) /* Clip at cluster boundary */
+ cc = fp->fs->csize - csect;
+ if (disk_write(fp->fs->drv, wbuff, sect, cc) != RES_OK)
+ ABORT(fp->fs, FR_DISK_ERR);
+#if _FS_MINIMIZE <= 2
+#if _FS_TINY
+ if (fp->fs->winsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */
+ mem_cpy(fp->fs->win, wbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), SS(fp->fs));
+ fp->fs->wflag = 0;
+ }
+#else
+ if (fp->dsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */
+ mem_cpy(fp->buf, wbuff + ((fp->dsect - sect) * SS(fp->fs)), SS(fp->fs));
+ fp->flag &= ~FA__DIRTY;
+ }
+#endif
+#endif
+ wcnt = SS(fp->fs) * cc; /* Number of bytes transferred */
+ continue;
+ }
+#if _FS_TINY
+ if (fp->fptr >= fp->fsize) { /* Avoid silly cache filling at growing edge */
+ if (sync_window(fp->fs)) ABORT(fp->fs, FR_DISK_ERR);
+ fp->fs->winsect = sect;
+ }
+#else
+ if (fp->dsect != sect) { /* Fill sector cache with file data */
+ if (fp->fptr < fp->fsize &&
+ disk_read(fp->fs->drv, fp->buf, sect, 1) != RES_OK)
+ ABORT(fp->fs, FR_DISK_ERR);
+ }
+#endif
+ fp->dsect = sect;
+ }
+ wcnt = SS(fp->fs) - ((UINT)fp->fptr % SS(fp->fs));/* Put partial sector into file I/O buffer */
+ if (wcnt > btw) wcnt = btw;
+#if _FS_TINY
+ if (move_window(fp->fs, fp->dsect) != FR_OK) /* Move sector window */
+ ABORT(fp->fs, FR_DISK_ERR);
+ mem_cpy(&fp->fs->win[fp->fptr % SS(fp->fs)], wbuff, wcnt); /* Fit partial sector */
+ fp->fs->wflag = 1;
+#else
+ mem_cpy(&fp->buf[fp->fptr % SS(fp->fs)], wbuff, wcnt); /* Fit partial sector */
+ fp->flag |= FA__DIRTY;
+#endif
+ }
+
+ if (fp->fptr > fp->fsize) fp->fsize = fp->fptr; /* Update file size if needed */
+ fp->flag |= FA__WRITTEN; /* Set file change flag */
+
+ LEAVE_FF(fp->fs, FR_OK);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Synchronize the File */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_sync (
+ FIL* fp /* Pointer to the file object */
+)
+{
+ FRESULT res;
+ DWORD tm;
+ BYTE *dir;
+
+
+ res = validate(fp); /* Check validity of the object */
+ if (res == FR_OK) {
+ if (fp->flag & FA__WRITTEN) { /* Has the file been written? */
+ /* Write-back dirty buffer */
+#if !_FS_TINY
+ if (fp->flag & FA__DIRTY) {
+ if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
+ LEAVE_FF(fp->fs, FR_DISK_ERR);
+ fp->flag &= ~FA__DIRTY;
+ }
+#endif
+ /* Update the directory entry */
+ res = move_window(fp->fs, fp->dir_sect);
+ if (res == FR_OK) {
+ dir = fp->dir_ptr;
+ dir[DIR_Attr] |= AM_ARC; /* Set archive bit */
+ ST_DWORD(dir + DIR_FileSize, fp->fsize); /* Update file size */
+ st_clust(dir, fp->sclust); /* Update start cluster */
+ tm = GET_FATTIME(); /* Update updated time */
+ ST_DWORD(dir + DIR_WrtTime, tm);
+ ST_WORD(dir + DIR_LstAccDate, 0);
+ fp->flag &= ~FA__WRITTEN;
+ fp->fs->wflag = 1;
+ res = sync_fs(fp->fs);
+ }
+ }
+ }
+
+ LEAVE_FF(fp->fs, res);
+}
+
+#endif /* !_FS_READONLY */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Close File */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_close (
+ FIL *fp /* Pointer to the file object to be closed */
+)
+{
+ FRESULT res;
+
+
+#if !_FS_READONLY
+ res = f_sync(fp); /* Flush cached data */
+ if (res == FR_OK)
+#endif
+ {
+ res = validate(fp); /* Lock volume */
+ if (res == FR_OK) {
+#if _FS_REENTRANT
+ FATFS *fs = fp->fs;
+#endif
+#if _FS_LOCK
+ res = dec_lock(fp->lockid); /* Decrement file open counter */
+ if (res == FR_OK)
+#endif
+ fp->fs = 0; /* Invalidate file object */
+#if _FS_REENTRANT
+ unlock_fs(fs, FR_OK); /* Unlock volume */
+#endif
+ }
+ }
+ return res;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Change Current Directory or Current Drive, Get Current Directory */
+/*-----------------------------------------------------------------------*/
+
+#if _FS_RPATH >= 1
+#if _VOLUMES >= 2
+FRESULT f_chdrive (
+ const TCHAR* path /* Drive number */
+)
+{
+ int vol;
+
+
+ vol = get_ldnumber(&path);
+ if (vol < 0) return FR_INVALID_DRIVE;
+
+ CurrVol = (BYTE)vol;
+
+ return FR_OK;
+}
+#endif
+
+
+FRESULT f_chdir (
+ const TCHAR* path /* Pointer to the directory path */
+)
+{
+ FRESULT res;
+ DIR dj;
+ DEFINE_NAMEBUF;
+
+
+ /* Get logical drive number */
+ res = find_volume(&dj.fs, &path, 0);
+ if (res == FR_OK) {
+ INIT_BUF(dj);
+ res = follow_path(&dj, path); /* Follow the path */
+ FREE_BUF();
+ if (res == FR_OK) { /* Follow completed */
+ if (!dj.dir) {
+ dj.fs->cdir = dj.sclust; /* Start directory itself */
+ } else {
+ if (dj.dir[DIR_Attr] & AM_DIR) /* Reached to the directory */
+ dj.fs->cdir = ld_clust(dj.fs, dj.dir);
+ else
+ res = FR_NO_PATH; /* Reached but a file */
+ }
+ }
+ if (res == FR_NO_FILE) res = FR_NO_PATH;
+ }
+
+ LEAVE_FF(dj.fs, res);
+}
+
+
+#if _FS_RPATH >= 2
+FRESULT f_getcwd (
+ TCHAR* buff, /* Pointer to the directory path */
+ UINT len /* Size of path */
+)
+{
+ FRESULT res;
+ DIR dj;
+ UINT i, n;
+ DWORD ccl;
+ TCHAR *tp;
+ FILINFO fno;
+ DEFINE_NAMEBUF;
+
+
+ *buff = 0;
+ /* Get logical drive number */
+ res = find_volume(&dj.fs, (const TCHAR**)&buff, 0); /* Get current volume */
+ if (res == FR_OK) {
+ INIT_BUF(dj);
+ i = len; /* Bottom of buffer (directory stack base) */
+ dj.sclust = dj.fs->cdir; /* Start to follow upper directory from current directory */
+ while ((ccl = dj.sclust) != 0) { /* Repeat while current directory is a sub-directory */
+ res = dir_sdi(&dj, 1); /* Get parent directory */
+ if (res != FR_OK) break;
+ res = dir_read(&dj, 0);
+ if (res != FR_OK) break;
+ dj.sclust = ld_clust(dj.fs, dj.dir); /* Goto parent directory */
+ res = dir_sdi(&dj, 0);
+ if (res != FR_OK) break;
+ do { /* Find the entry links to the child directory */
+ res = dir_read(&dj, 0);
+ if (res != FR_OK) break;
+ if (ccl == ld_clust(dj.fs, dj.dir)) break; /* Found the entry */
+ res = dir_next(&dj, 0);
+ } while (res == FR_OK);
+ if (res == FR_NO_FILE) res = FR_INT_ERR;/* It cannot be 'not found'. */
+ if (res != FR_OK) break;
+#if _USE_LFN
+ fno.lfname = buff;
+ fno.lfsize = i;
+#endif
+ get_fileinfo(&dj, &fno); /* Get the directory name and push it to the buffer */
+ tp = fno.fname;
+#if _USE_LFN
+ if (*buff) tp = buff;
+#endif
+ for (n = 0; tp[n]; n++) ;
+ if (i < n + 3) {
+ res = FR_NOT_ENOUGH_CORE; break;
+ }
+ while (n) buff[--i] = tp[--n];
+ buff[--i] = '/';
+ }
+ tp = buff;
+ if (res == FR_OK) {
+#if _VOLUMES >= 2
+ *tp++ = '0' + CurrVol; /* Put drive number */
+ *tp++ = ':';
+#endif
+ if (i == len) { /* Root-directory */
+ *tp++ = '/';
+ } else { /* Sub-directroy */
+ do /* Add stacked path str */
+ *tp++ = buff[i++];
+ while (i < len);
+ }
+ }
+ *tp = 0;
+ FREE_BUF();
+ }
+
+ LEAVE_FF(dj.fs, res);
+}
+#endif /* _FS_RPATH >= 2 */
+#endif /* _FS_RPATH >= 1 */
+
+
+
+#if _FS_MINIMIZE <= 2
+/*-----------------------------------------------------------------------*/
+/* Seek File R/W Pointer */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_lseek (
+ FIL* fp, /* Pointer to the file object */
+ DWORD ofs /* File pointer from top of file */
+)
+{
+ FRESULT res;
+ DWORD clst, bcs, nsect, ifptr;
+#if _USE_FASTSEEK
+ DWORD cl, pcl, ncl, tcl, dsc, tlen, ulen, *tbl;
+#endif
+
+
+ res = validate(fp); /* Check validity of the object */
+ if (res != FR_OK) LEAVE_FF(fp->fs, res);
+ if (fp->err) /* Check error */
+ LEAVE_FF(fp->fs, (FRESULT)fp->err);
+
+#if _USE_FASTSEEK
+ if (fp->cltbl) { /* Fast seek */
+ if (ofs == CREATE_LINKMAP) { /* Create CLMT */
+ tbl = fp->cltbl;
+ tlen = *tbl++; ulen = 2; /* Given table size and required table size */
+ cl = fp->sclust; /* Top of the chain */
+ if (cl) {
+ do {
+ /* Get a fragment */
+ tcl = cl; ncl = 0; ulen += 2; /* Top, length and used items */
+ do {
+ pcl = cl; ncl++;
+ cl = get_fat(fp->fs, cl);
+ if (cl <= 1) ABORT(fp->fs, FR_INT_ERR);
+ if (cl == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
+ } while (cl == pcl + 1);
+ if (ulen <= tlen) { /* Store the length and top of the fragment */
+ *tbl++ = ncl; *tbl++ = tcl;
+ }
+ } while (cl < fp->fs->n_fatent); /* Repeat until end of chain */
+ }
+ *fp->cltbl = ulen; /* Number of items used */
+ if (ulen <= tlen)
+ *tbl = 0; /* Terminate table */
+ else
+ res = FR_NOT_ENOUGH_CORE; /* Given table size is smaller than required */
+
+ } else { /* Fast seek */
+ if (ofs > fp->fsize) /* Clip offset at the file size */
+ ofs = fp->fsize;
+ fp->fptr = ofs; /* Set file pointer */
+ if (ofs) {
+ fp->clust = clmt_clust(fp, ofs - 1);
+ dsc = clust2sect(fp->fs, fp->clust);
+ if (!dsc) ABORT(fp->fs, FR_INT_ERR);
+ dsc += (ofs - 1) / SS(fp->fs) & (fp->fs->csize - 1);
+ if (fp->fptr % SS(fp->fs) && dsc != fp->dsect) { /* Refill sector cache if needed */
+#if !_FS_TINY
+#if !_FS_READONLY
+ if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */
+ if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
+ ABORT(fp->fs, FR_DISK_ERR);
+ fp->flag &= ~FA__DIRTY;
+ }
+#endif
+ if (disk_read(fp->fs->drv, fp->buf, dsc, 1) != RES_OK) /* Load current sector */
+ ABORT(fp->fs, FR_DISK_ERR);
+#endif
+ fp->dsect = dsc;
+ }
+ }
+ }
+ } else
+#endif
+
+ /* Normal Seek */
+ {
+ if (ofs > fp->fsize /* In read-only mode, clip offset with the file size */
+#if !_FS_READONLY
+ && !(fp->flag & FA_WRITE)
+#endif
+ ) ofs = fp->fsize;
+
+ ifptr = fp->fptr;
+ fp->fptr = nsect = 0;
+ if (ofs) {
+ bcs = (DWORD)fp->fs->csize * SS(fp->fs); /* Cluster size (byte) */
+ if (ifptr > 0 &&
+ (ofs - 1) / bcs >= (ifptr - 1) / bcs) { /* When seek to same or following cluster, */
+ fp->fptr = (ifptr - 1) & ~(bcs - 1); /* start from the current cluster */
+ ofs -= fp->fptr;
+ clst = fp->clust;
+ } else { /* When seek to back cluster, */
+ clst = fp->sclust; /* start from the first cluster */
+#if !_FS_READONLY
+ if (clst == 0) { /* If no cluster chain, create a new chain */
+ clst = create_chain(fp->fs, 0);
+ if (clst == 1) ABORT(fp->fs, FR_INT_ERR);
+ if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
+ fp->sclust = clst;
+ }
+#endif
+ fp->clust = clst;
+ }
+ if (clst != 0) {
+ while (ofs > bcs) { /* Cluster following loop */
+#if !_FS_READONLY
+ if (fp->flag & FA_WRITE) { /* Check if in write mode or not */
+ clst = create_chain(fp->fs, clst); /* Force stretch if in write mode */
+ if (clst == 0) { /* When disk gets full, clip file size */
+ ofs = bcs; break;
+ }
+ } else
+#endif
+ clst = get_fat(fp->fs, clst); /* Follow cluster chain if not in write mode */
+ if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
+ if (clst <= 1 || clst >= fp->fs->n_fatent) ABORT(fp->fs, FR_INT_ERR);
+ fp->clust = clst;
+ fp->fptr += bcs;
+ ofs -= bcs;
+ }
+ fp->fptr += ofs;
+ if (ofs % SS(fp->fs)) {
+ nsect = clust2sect(fp->fs, clst); /* Current sector */
+ if (!nsect) ABORT(fp->fs, FR_INT_ERR);
+ nsect += ofs / SS(fp->fs);
+ }
+ }
+ }
+ if (fp->fptr % SS(fp->fs) && nsect != fp->dsect) { /* Fill sector cache if needed */
+#if !_FS_TINY
+#if !_FS_READONLY
+ if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */
+ if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
+ ABORT(fp->fs, FR_DISK_ERR);
+ fp->flag &= ~FA__DIRTY;
+ }
+#endif
+ if (disk_read(fp->fs->drv, fp->buf, nsect, 1) != RES_OK) /* Fill sector cache */
+ ABORT(fp->fs, FR_DISK_ERR);
+#endif
+ fp->dsect = nsect;
+ }
+#if !_FS_READONLY
+ if (fp->fptr > fp->fsize) { /* Set file change flag if the file size is extended */
+ fp->fsize = fp->fptr;
+ fp->flag |= FA__WRITTEN;
+ }
+#endif
+ }
+
+ LEAVE_FF(fp->fs, res);
+}
+
+
+
+#if _FS_MINIMIZE <= 1
+/*-----------------------------------------------------------------------*/
+/* Create a Directory Object */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_opendir (
+ DIR* dp, /* Pointer to directory object to create */
+ const TCHAR* path /* Pointer to the directory path */
+)
+{
+ FRESULT res;
+ FATFS* fs;
+ DEFINE_NAMEBUF;
+
+
+ if (!dp) return FR_INVALID_OBJECT;
+
+ /* Get logical drive number */
+ res = find_volume(&fs, &path, 0);
+ if (res == FR_OK) {
+ dp->fs = fs;
+ INIT_BUF(*dp);
+ res = follow_path(dp, path); /* Follow the path to the directory */
+ FREE_BUF();
+ if (res == FR_OK) { /* Follow completed */
+ if (dp->dir) { /* It is not the origin directory itself */
+ if (dp->dir[DIR_Attr] & AM_DIR) /* The object is a sub directory */
+ dp->sclust = ld_clust(fs, dp->dir);
+ else /* The object is a file */
+ res = FR_NO_PATH;
+ }
+ if (res == FR_OK) {
+ dp->id = fs->id;
+ res = dir_sdi(dp, 0); /* Rewind directory */
+#if _FS_LOCK
+ if (res == FR_OK) {
+ if (dp->sclust) {
+ dp->lockid = inc_lock(dp, 0); /* Lock the sub directory */
+ if (!dp->lockid)
+ res = FR_TOO_MANY_OPEN_FILES;
+ } else {
+ dp->lockid = 0; /* Root directory need not to be locked */
+ }
+ }
+#endif
+ }
+ }
+ if (res == FR_NO_FILE) res = FR_NO_PATH;
+ }
+ if (res != FR_OK) dp->fs = 0; /* Invalidate the directory object if function faild */
+
+ LEAVE_FF(fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Close Directory */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_closedir (
+ DIR *dp /* Pointer to the directory object to be closed */
+)
+{
+ FRESULT res;
+
+
+ res = validate(dp);
+ if (res == FR_OK) {
+#if _FS_REENTRANT
+ FATFS *fs = dp->fs;
+#endif
+#if _FS_LOCK
+ if (dp->lockid) /* Decrement sub-directory open counter */
+ res = dec_lock(dp->lockid);
+ if (res == FR_OK)
+#endif
+ dp->fs = 0; /* Invalidate directory object */
+#if _FS_REENTRANT
+ unlock_fs(fs, FR_OK); /* Unlock volume */
+#endif
+ }
+ return res;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Read Directory Entries in Sequence */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_readdir (
+ DIR* dp, /* Pointer to the open directory object */
+ FILINFO* fno /* Pointer to file information to return */
+)
+{
+ FRESULT res;
+ DEFINE_NAMEBUF;
+
+
+ res = validate(dp); /* Check validity of the object */
+ if (res == FR_OK) {
+ if (!fno) {
+ res = dir_sdi(dp, 0); /* Rewind the directory object */
+ } else {
+ INIT_BUF(*dp);
+ res = dir_read(dp, 0); /* Read an item */
+ if (res == FR_NO_FILE) { /* Reached end of directory */
+ dp->sect = 0;
+ res = FR_OK;
+ }
+ if (res == FR_OK) { /* A valid entry is found */
+ get_fileinfo(dp, fno); /* Get the object information */
+ res = dir_next(dp, 0); /* Increment index for next */
+ if (res == FR_NO_FILE) {
+ dp->sect = 0;
+ res = FR_OK;
+ }
+ }
+ FREE_BUF();
+ }
+ }
+
+ LEAVE_FF(dp->fs, res);
+}
+
+
+
+#if _USE_FIND
+/*-----------------------------------------------------------------------*/
+/* Find next file */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_findnext (
+ DIR* dp, /* Pointer to the open directory object */
+ FILINFO* fno /* Pointer to the file information structure */
+)
+{
+ FRESULT res;
+
+
+ for (;;) {
+ res = f_readdir(dp, fno); /* Get a directory item */
+ if (res != FR_OK || !fno || !fno->fname[0]) break; /* Terminate if any error or end of directory */
+#if _USE_LFN
+ if (fno->lfname && pattern_matching(dp->pat, fno->lfname, 0, 0)) break; /* Test for LFN if exist */
+#endif
+ if (pattern_matching(dp->pat, fno->fname, 0, 0)) break; /* Test for SFN */
+ }
+ return res;
+
+}
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Find first file */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_findfirst (
+ DIR* dp, /* Pointer to the blank directory object */
+ FILINFO* fno, /* Pointer to the file information structure */
+ const TCHAR* path, /* Pointer to the directory to open */
+ const TCHAR* pattern /* Pointer to the matching pattern */
+)
+{
+ FRESULT res;
+
+
+ dp->pat = pattern; /* Save pointer to pattern string */
+ res = f_opendir(dp, path); /* Open the target directory */
+ if (res == FR_OK)
+ res = f_findnext(dp, fno); /* Find the first item */
+ return res;
+}
+
+#endif /* _USE_FIND */
+
+
+
+#if _FS_MINIMIZE == 0
+/*-----------------------------------------------------------------------*/
+/* Get File Status */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_stat (
+ const TCHAR* path, /* Pointer to the file path */
+ FILINFO* fno /* Pointer to file information to return */
+)
+{
+ FRESULT res;
+ DIR dj;
+ DEFINE_NAMEBUF;
+
+
+ /* Get logical drive number */
+ res = find_volume(&dj.fs, &path, 0);
+ if (res == FR_OK) {
+ INIT_BUF(dj);
+ res = follow_path(&dj, path); /* Follow the file path */
+ if (res == FR_OK) { /* Follow completed */
+ if (dj.dir) { /* Found an object */
+ if (fno) get_fileinfo(&dj, fno);
+ } else { /* It is root directory */
+ res = FR_INVALID_NAME;
+ }
+ }
+ FREE_BUF();
+ }
+
+ LEAVE_FF(dj.fs, res);
+}
+
+
+
+#if !_FS_READONLY
+/*-----------------------------------------------------------------------*/
+/* Get Number of Free Clusters */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_getfree (
+ const TCHAR* path, /* Path name of the logical drive number */
+ DWORD* nclst, /* Pointer to a variable to return number of free clusters */
+ FATFS** fatfs /* Pointer to return pointer to corresponding file system object */
+)
+{
+ FRESULT res;
+ FATFS *fs;
+ DWORD n, clst, sect, stat;
+ UINT i;
+ BYTE fat, *p;
+
+
+ /* Get logical drive number */
+ res = find_volume(fatfs, &path, 0);
+ fs = *fatfs;
+ if (res == FR_OK) {
+ /* If free_clust is valid, return it without full cluster scan */
+ if (fs->free_clust <= fs->n_fatent - 2) {
+ *nclst = fs->free_clust;
+ } else {
+ /* Get number of free clusters */
+ fat = fs->fs_type;
+ n = 0;
+ if (fat == FS_FAT12) {
+ clst = 2;
+ do {
+ stat = get_fat(fs, clst);
+ if (stat == 0xFFFFFFFF) { res = FR_DISK_ERR; break; }
+ if (stat == 1) { res = FR_INT_ERR; break; }
+ if (stat == 0) n++;
+ } while (++clst < fs->n_fatent);
+ } else {
+ clst = fs->n_fatent;
+ sect = fs->fatbase;
+ i = 0; p = 0;
+ do {
+ if (!i) {
+ res = move_window(fs, sect++);
+ if (res != FR_OK) break;
+ p = fs->win;
+ i = SS(fs);
+ }
+ if (fat == FS_FAT16) {
+ if (LD_WORD(p) == 0) n++;
+ p += 2; i -= 2;
+ } else {
+ if ((LD_DWORD(p) & 0x0FFFFFFF) == 0) n++;
+ p += 4; i -= 4;
+ }
+ } while (--clst);
+ }
+ fs->free_clust = n;
+ fs->fsi_flag |= 1;
+ *nclst = n;
+ }
+ }
+ LEAVE_FF(fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Truncate File */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_truncate (
+ FIL* fp /* Pointer to the file object */
+)
+{
+ FRESULT res;
+ DWORD ncl;
+
+
+ res = validate(fp); /* Check validity of the object */
+ if (res == FR_OK) {
+ if (fp->err) { /* Check error */
+ res = (FRESULT)fp->err;
+ } else {
+ if (!(fp->flag & FA_WRITE)) /* Check access mode */
+ res = FR_DENIED;
+ }
+ }
+ if (res == FR_OK) {
+ if (fp->fsize > fp->fptr) {
+ fp->fsize = fp->fptr; /* Set file size to current R/W point */
+ fp->flag |= FA__WRITTEN;
+ if (fp->fptr == 0) { /* When set file size to zero, remove entire cluster chain */
+ res = remove_chain(fp->fs, fp->sclust);
+ fp->sclust = 0;
+ } else { /* When truncate a part of the file, remove remaining clusters */
+ ncl = get_fat(fp->fs, fp->clust);
+ res = FR_OK;
+ if (ncl == 0xFFFFFFFF) res = FR_DISK_ERR;
+ if (ncl == 1) res = FR_INT_ERR;
+ if (res == FR_OK && ncl < fp->fs->n_fatent) {
+ res = put_fat(fp->fs, fp->clust, 0x0FFFFFFF);
+ if (res == FR_OK) res = remove_chain(fp->fs, ncl);
+ }
+ }
+#if !_FS_TINY
+ if (res == FR_OK && (fp->flag & FA__DIRTY)) {
+ if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
+ res = FR_DISK_ERR;
+ else
+ fp->flag &= ~FA__DIRTY;
+ }
+#endif
+ }
+ if (res != FR_OK) fp->err = (FRESULT)res;
+ }
+
+ LEAVE_FF(fp->fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Delete a File or Directory */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_unlink (
+ const TCHAR* path /* Pointer to the file or directory path */
+)
+{
+ FRESULT res;
+ DIR dj, sdj;
+ BYTE *dir;
+ DWORD dclst = 0;
+ DEFINE_NAMEBUF;
+
+
+ /* Get logical drive number */
+ res = find_volume(&dj.fs, &path, 1);
+ if (res == FR_OK) {
+ INIT_BUF(dj);
+ res = follow_path(&dj, path); /* Follow the file path */
+ if (_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT))
+ res = FR_INVALID_NAME; /* Cannot remove dot entry */
+#if _FS_LOCK
+ if (res == FR_OK) res = chk_lock(&dj, 2); /* Cannot remove open object */
+#endif
+ if (res == FR_OK) { /* The object is accessible */
+ dir = dj.dir;
+ if (!dir) {
+ res = FR_INVALID_NAME; /* Cannot remove the origin directory */
+ } else {
+ if (dir[DIR_Attr] & AM_RDO)
+ res = FR_DENIED; /* Cannot remove R/O object */
+ }
+ if (res == FR_OK) {
+ dclst = ld_clust(dj.fs, dir);
+ if (dclst && (dir[DIR_Attr] & AM_DIR)) { /* Is it a sub-directory ? */
+#if _FS_RPATH
+ if (dclst == dj.fs->cdir) { /* Is it the current directory? */
+ res = FR_DENIED;
+ } else
+#endif
+ {
+ mem_cpy(&sdj, &dj, sizeof (DIR)); /* Open the sub-directory */
+ sdj.sclust = dclst;
+ res = dir_sdi(&sdj, 2);
+ if (res == FR_OK) {
+ res = dir_read(&sdj, 0); /* Read an item (excluding dot entries) */
+ if (res == FR_OK) res = FR_DENIED; /* Not empty? (cannot remove) */
+ if (res == FR_NO_FILE) res = FR_OK; /* Empty? (can remove) */
+ }
+ }
+ }
+ }
+ if (res == FR_OK) {
+ res = dir_remove(&dj); /* Remove the directory entry */
+ if (res == FR_OK && dclst) /* Remove the cluster chain if exist */
+ res = remove_chain(dj.fs, dclst);
+ if (res == FR_OK) res = sync_fs(dj.fs);
+ }
+ }
+ FREE_BUF();
+ }
+
+ LEAVE_FF(dj.fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Create a Directory */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_mkdir (
+ const TCHAR* path /* Pointer to the directory path */
+)
+{
+ FRESULT res;
+ DIR dj;
+ BYTE *dir, n;
+ DWORD dsc, dcl, pcl, tm = GET_FATTIME();
+ DEFINE_NAMEBUF;
+
+
+ /* Get logical drive number */
+ res = find_volume(&dj.fs, &path, 1);
+ if (res == FR_OK) {
+ INIT_BUF(dj);
+ res = follow_path(&dj, path); /* Follow the file path */
+ if (res == FR_OK) res = FR_EXIST; /* Any object with same name is already existing */
+ if (_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT))
+ res = FR_INVALID_NAME;
+ if (res == FR_NO_FILE) { /* Can create a new directory */
+ dcl = create_chain(dj.fs, 0); /* Allocate a cluster for the new directory table */
+ res = FR_OK;
+ if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster */
+ if (dcl == 1) res = FR_INT_ERR;
+ if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR;
+ if (res == FR_OK) /* Flush FAT */
+ res = sync_window(dj.fs);
+ if (res == FR_OK) { /* Initialize the new directory table */
+ dsc = clust2sect(dj.fs, dcl);
+ dir = dj.fs->win;
+ mem_set(dir, 0, SS(dj.fs));
+ mem_set(dir + DIR_Name, ' ', 11); /* Create "." entry */
+ dir[DIR_Name] = '.';
+ dir[DIR_Attr] = AM_DIR;
+ ST_DWORD(dir + DIR_WrtTime, tm);
+ st_clust(dir, dcl);
+ mem_cpy(dir + SZ_DIRE, dir, SZ_DIRE); /* Create ".." entry */
+ dir[SZ_DIRE + 1] = '.'; pcl = dj.sclust;
+ if (dj.fs->fs_type == FS_FAT32 && pcl == dj.fs->dirbase)
+ pcl = 0;
+ st_clust(dir + SZ_DIRE, pcl);
+ for (n = dj.fs->csize; n; n--) { /* Write dot entries and clear following sectors */
+ dj.fs->winsect = dsc++;
+ dj.fs->wflag = 1;
+ res = sync_window(dj.fs);
+ if (res != FR_OK) break;
+ mem_set(dir, 0, SS(dj.fs));
+ }
+ }
+ if (res == FR_OK) res = dir_register(&dj); /* Register the object to the directoy */
+ if (res != FR_OK) {
+ remove_chain(dj.fs, dcl); /* Could not register, remove cluster chain */
+ } else {
+ dir = dj.dir;
+ dir[DIR_Attr] = AM_DIR; /* Attribute */
+ ST_DWORD(dir + DIR_WrtTime, tm); /* Created time */
+ st_clust(dir, dcl); /* Table start cluster */
+ dj.fs->wflag = 1;
+ res = sync_fs(dj.fs);
+ }
+ }
+ FREE_BUF();
+ }
+
+ LEAVE_FF(dj.fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Change Attribute */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_chmod (
+ const TCHAR* path, /* Pointer to the file path */
+ BYTE attr, /* Attribute bits */
+ BYTE mask /* Attribute mask to change */
+)
+{
+ FRESULT res;
+ DIR dj;
+ BYTE *dir;
+ DEFINE_NAMEBUF;
+
+
+ /* Get logical drive number */
+ res = find_volume(&dj.fs, &path, 1);
+ if (res == FR_OK) {
+ INIT_BUF(dj);
+ res = follow_path(&dj, path); /* Follow the file path */
+ FREE_BUF();
+ if (_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT))
+ res = FR_INVALID_NAME;
+ if (res == FR_OK) {
+ dir = dj.dir;
+ if (!dir) { /* Is it a root directory? */
+ res = FR_INVALID_NAME;
+ } else { /* File or sub directory */
+ mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC; /* Valid attribute mask */
+ dir[DIR_Attr] = (attr & mask) | (dir[DIR_Attr] & (BYTE)~mask); /* Apply attribute change */
+ dj.fs->wflag = 1;
+ res = sync_fs(dj.fs);
+ }
+ }
+ }
+
+ LEAVE_FF(dj.fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Rename File/Directory */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_rename (
+ const TCHAR* path_old, /* Pointer to the object to be renamed */
+ const TCHAR* path_new /* Pointer to the new name */
+)
+{
+ FRESULT res;
+ DIR djo, djn;
+ BYTE buf[21], *dir;
+ DWORD dw;
+ DEFINE_NAMEBUF;
+
+
+ /* Get logical drive number of the source object */
+ res = find_volume(&djo.fs, &path_old, 1);
+ if (res == FR_OK) {
+ djn.fs = djo.fs;
+ INIT_BUF(djo);
+ res = follow_path(&djo, path_old); /* Check old object */
+ if (_FS_RPATH && res == FR_OK && (djo.fn[NSFLAG] & NS_DOT))
+ res = FR_INVALID_NAME;
+#if _FS_LOCK
+ if (res == FR_OK) res = chk_lock(&djo, 2);
+#endif
+ if (res == FR_OK) { /* Old object is found */
+ if (!djo.dir) { /* Is root dir? */
+ res = FR_NO_FILE;
+ } else {
+ mem_cpy(buf, djo.dir + DIR_Attr, 21); /* Save information about object except name */
+ mem_cpy(&djn, &djo, sizeof (DIR)); /* Duplicate the directory object */
+ if (get_ldnumber(&path_new) >= 0) /* Snip drive number off and ignore it */
+ res = follow_path(&djn, path_new); /* and make sure if new object name is not conflicting */
+ else
+ res = FR_INVALID_DRIVE;
+ if (res == FR_OK) res = FR_EXIST; /* The new object name is already existing */
+ if (res == FR_NO_FILE) { /* It is a valid path and no name collision */
+ res = dir_register(&djn); /* Register the new entry */
+ if (res == FR_OK) {
+/* Start of critical section where any interruption can cause a cross-link */
+ dir = djn.dir; /* Copy information about object except name */
+ mem_cpy(dir + 13, buf + 2, 19);
+ dir[DIR_Attr] = buf[0] | AM_ARC;
+ djo.fs->wflag = 1;
+ if ((dir[DIR_Attr] & AM_DIR) && djo.sclust != djn.sclust) { /* Update .. entry in the sub-directory if needed */
+ dw = clust2sect(djo.fs, ld_clust(djo.fs, dir));
+ if (!dw) {
+ res = FR_INT_ERR;
+ } else {
+ res = move_window(djo.fs, dw);
+ dir = djo.fs->win + SZ_DIRE * 1; /* Ptr to .. entry */
+ if (res == FR_OK && dir[1] == '.') {
+ st_clust(dir, djn.sclust);
+ djo.fs->wflag = 1;
+ }
+ }
+ }
+ if (res == FR_OK) {
+ res = dir_remove(&djo); /* Remove old entry */
+ if (res == FR_OK)
+ res = sync_fs(djo.fs);
+ }
+/* End of critical section */
+ }
+ }
+ }
+ }
+ FREE_BUF();
+ }
+
+ LEAVE_FF(djo.fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Change Timestamp */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_utime (
+ const TCHAR* path, /* Pointer to the file/directory name */
+ const FILINFO* fno /* Pointer to the time stamp to be set */
+)
+{
+ FRESULT res;
+ DIR dj;
+ BYTE *dir;
+ DEFINE_NAMEBUF;
+
+
+ /* Get logical drive number */
+ res = find_volume(&dj.fs, &path, 1);
+ if (res == FR_OK) {
+ INIT_BUF(dj);
+ res = follow_path(&dj, path); /* Follow the file path */
+ FREE_BUF();
+ if (_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT))
+ res = FR_INVALID_NAME;
+ if (res == FR_OK) {
+ dir = dj.dir;
+ if (!dir) { /* Root directory */
+ res = FR_INVALID_NAME;
+ } else { /* File or sub-directory */
+ ST_WORD(dir + DIR_WrtTime, fno->ftime);
+ ST_WORD(dir + DIR_WrtDate, fno->fdate);
+ dj.fs->wflag = 1;
+ res = sync_fs(dj.fs);
+ }
+ }
+ }
+
+ LEAVE_FF(dj.fs, res);
+}
+
+#endif /* !_FS_READONLY */
+#endif /* _FS_MINIMIZE == 0 */
+#endif /* _FS_MINIMIZE <= 1 */
+#endif /* _FS_MINIMIZE <= 2 */
+
+
+
+
+#if _USE_LABEL
+/*-----------------------------------------------------------------------*/
+/* Get volume label */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_getlabel (
+ const TCHAR* path, /* Path name of the logical drive number */
+ TCHAR* label, /* Pointer to a buffer to return the volume label */
+ DWORD* vsn /* Pointer to a variable to return the volume serial number */
+)
+{
+ FRESULT res;
+ DIR dj;
+ UINT i, j;
+#if _USE_LFN && _LFN_UNICODE
+ WCHAR w;
+#endif
+
+
+ /* Get logical drive number */
+ res = find_volume(&dj.fs, &path, 0);
+
+ /* Get volume label */
+ if (res == FR_OK && label) {
+ dj.sclust = 0; /* Open root directory */
+ res = dir_sdi(&dj, 0);
+ if (res == FR_OK) {
+ res = dir_read(&dj, 1); /* Get an entry with AM_VOL */
+ if (res == FR_OK) { /* A volume label is exist */
+#if _USE_LFN && _LFN_UNICODE
+ i = j = 0;
+ do {
+ w = (i < 11) ? dj.dir[i++] : ' ';
+ if (IsDBCS1(w) && i < 11 && IsDBCS2(dj.dir[i]))
+ w = w << 8 | dj.dir[i++];
+ label[j++] = ff_convert(w, 1); /* OEM -> Unicode */
+ } while (j < 11);
+#else
+ mem_cpy(label, dj.dir, 11);
+#endif
+ j = 11;
+ do {
+ label[j] = 0;
+ if (!j) break;
+ } while (label[--j] == ' ');
+ }
+ if (res == FR_NO_FILE) { /* No label, return nul string */
+ label[0] = 0;
+ res = FR_OK;
+ }
+ }
+ }
+
+ /* Get volume serial number */
+ if (res == FR_OK && vsn) {
+ res = move_window(dj.fs, dj.fs->volbase);
+ if (res == FR_OK) {
+ i = dj.fs->fs_type == FS_FAT32 ? BS_VolID32 : BS_VolID;
+ *vsn = LD_DWORD(&dj.fs->win[i]);
+ }
+ }
+
+ LEAVE_FF(dj.fs, res);
+}
+
+
+
+#if !_FS_READONLY
+/*-----------------------------------------------------------------------*/
+/* Set volume label */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_setlabel (
+ const TCHAR* label /* Pointer to the volume label to set */
+)
+{
+ FRESULT res;
+ DIR dj;
+ BYTE vn[11];
+ UINT i, j, sl;
+ WCHAR w;
+ DWORD tm;
+
+
+ /* Get logical drive number */
+ res = find_volume(&dj.fs, &label, 1);
+ if (res) LEAVE_FF(dj.fs, res);
+
+ /* Create a volume label in directory form */
+ vn[0] = 0;
+ for (sl = 0; label[sl]; sl++) ; /* Get name length */
+ for ( ; sl && label[sl - 1] == ' '; sl--) ; /* Remove trailing spaces */
+ if (sl) { /* Create volume label in directory form */
+ i = j = 0;
+ do {
+#if _USE_LFN && _LFN_UNICODE
+ w = ff_convert(ff_wtoupper(label[i++]), 0);
+#else
+ w = (BYTE)label[i++];
+ if (IsDBCS1(w))
+ w = (j < 10 && i < sl && IsDBCS2(label[i])) ? w << 8 | (BYTE)label[i++] : 0;
+#if _USE_LFN
+ w = ff_convert(ff_wtoupper(ff_convert(w, 1)), 0);
+#else
+ if (IsLower(w)) w -= 0x20; /* To upper ASCII characters */
+#ifdef _EXCVT
+ if (w >= 0x80) w = ExCvt[w - 0x80]; /* To upper extended characters (SBCS cfg) */
+#else
+ if (!_DF1S && w >= 0x80) w = 0; /* Reject extended characters (ASCII cfg) */
+#endif
+#endif
+#endif
+ if (!w || chk_chr("\"*+,.:;<=>\?[]|\x7F", w) || j >= (UINT)((w >= 0x100) ? 10 : 11)) /* Reject invalid characters for volume label */
+ LEAVE_FF(dj.fs, FR_INVALID_NAME);
+ if (w >= 0x100) vn[j++] = (BYTE)(w >> 8);
+ vn[j++] = (BYTE)w;
+ } while (i < sl);
+ while (j < 11) vn[j++] = ' '; /* Fill remaining name field */
+ if (vn[0] == DDEM) LEAVE_FF(dj.fs, FR_INVALID_NAME); /* Reject illegal name (heading DDEM) */
+ }
+
+ /* Set volume label */
+ dj.sclust = 0; /* Open root directory */
+ res = dir_sdi(&dj, 0);
+ if (res == FR_OK) {
+ res = dir_read(&dj, 1); /* Get an entry with AM_VOL */
+ if (res == FR_OK) { /* A volume label is found */
+ if (vn[0]) {
+ mem_cpy(dj.dir, vn, 11); /* Change the volume label name */
+ tm = GET_FATTIME();
+ ST_DWORD(dj.dir + DIR_WrtTime, tm);
+ } else {
+ dj.dir[0] = DDEM; /* Remove the volume label */
+ }
+ dj.fs->wflag = 1;
+ res = sync_fs(dj.fs);
+ } else { /* No volume label is found or error */
+ if (res == FR_NO_FILE) {
+ res = FR_OK;
+ if (vn[0]) { /* Create volume label as new */
+ res = dir_alloc(&dj, 1); /* Allocate an entry for volume label */
+ if (res == FR_OK) {
+ mem_set(dj.dir, 0, SZ_DIRE); /* Set volume label */
+ mem_cpy(dj.dir, vn, 11);
+ dj.dir[DIR_Attr] = AM_VOL;
+ tm = GET_FATTIME();
+ ST_DWORD(dj.dir + DIR_WrtTime, tm);
+ dj.fs->wflag = 1;
+ res = sync_fs(dj.fs);
+ }
+ }
+ }
+ }
+ }
+
+ LEAVE_FF(dj.fs, res);
+}
+
+#endif /* !_FS_READONLY */
+#endif /* _USE_LABEL */
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Forward data to the stream directly (available on only tiny cfg) */
+/*-----------------------------------------------------------------------*/
+#if _USE_FORWARD && _FS_TINY
+
+FRESULT f_forward (
+ FIL* fp, /* Pointer to the file object */
+ UINT (*func)(const BYTE*,UINT), /* Pointer to the streaming function */
+ UINT btf, /* Number of bytes to forward */
+ UINT* bf /* Pointer to number of bytes forwarded */
+)
+{
+ FRESULT res;
+ DWORD remain, clst, sect;
+ UINT rcnt;
+ BYTE csect;
+
+
+ *bf = 0; /* Clear transfer byte counter */
+
+ res = validate(fp); /* Check validity of the object */
+ if (res != FR_OK) LEAVE_FF(fp->fs, res);
+ if (fp->err) /* Check error */
+ LEAVE_FF(fp->fs, (FRESULT)fp->err);
+ if (!(fp->flag & FA_READ)) /* Check access mode */
+ LEAVE_FF(fp->fs, FR_DENIED);
+
+ remain = fp->fsize - fp->fptr;
+ if (btf > remain) btf = (UINT)remain; /* Truncate btf by remaining bytes */
+
+ for ( ; btf && (*func)(0, 0); /* Repeat until all data transferred or stream becomes busy */
+ fp->fptr += rcnt, *bf += rcnt, btf -= rcnt) {
+ csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */
+ if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */
+ if (!csect) { /* On the cluster boundary? */
+ clst = (fp->fptr == 0) ? /* On the top of the file? */
+ fp->sclust : get_fat(fp->fs, fp->clust);
+ if (clst <= 1) ABORT(fp->fs, FR_INT_ERR);
+ if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
+ fp->clust = clst; /* Update current cluster */
+ }
+ }
+ sect = clust2sect(fp->fs, fp->clust); /* Get current data sector */
+ if (!sect) ABORT(fp->fs, FR_INT_ERR);
+ sect += csect;
+ if (move_window(fp->fs, sect) != FR_OK) /* Move sector window */
+ ABORT(fp->fs, FR_DISK_ERR);
+ fp->dsect = sect;
+ rcnt = SS(fp->fs) - (WORD)(fp->fptr % SS(fp->fs)); /* Forward data from sector window */
+ if (rcnt > btf) rcnt = btf;
+ rcnt = (*func)(&fp->fs->win[(WORD)fp->fptr % SS(fp->fs)], rcnt);
+ if (!rcnt) ABORT(fp->fs, FR_INT_ERR);
+ }
+
+ LEAVE_FF(fp->fs, FR_OK);
+}
+#endif /* _USE_FORWARD */
+
+
+
+#if _USE_MKFS && !_FS_READONLY
+/*-----------------------------------------------------------------------*/
+/* Create file system on the logical drive */
+/*-----------------------------------------------------------------------*/
+#define N_ROOTDIR 512 /* Number of root directory entries for FAT12/16 */
+#define N_FATS 1 /* Number of FATs (1 or 2) */
+
+
+FRESULT f_mkfs (
+ const TCHAR* path, /* Logical drive number */
+ BYTE sfd, /* Partitioning rule 0:FDISK, 1:SFD */
+ UINT au /* Size of allocation unit in unit of byte or sector */
+)
+{
+ static const WORD vst[] = { 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 0};
+ static const WORD cst[] = {32768, 16384, 8192, 4096, 2048, 16384, 8192, 4096, 2048, 1024, 512};
+ int vol;
+ BYTE fmt, md, sys, *tbl, pdrv, part;
+ DWORD n_clst, vs, n, wsect;
+ UINT i;
+ DWORD b_vol, b_fat, b_dir, b_data; /* LBA */
+ DWORD n_vol, n_rsv, n_fat, n_dir; /* Size */
+ FATFS *fs;
+ DSTATUS stat;
+#if _USE_TRIM
+ DWORD eb[2];
+#endif
+
+
+ /* Check mounted drive and clear work area */
+ if (sfd > 1) return FR_INVALID_PARAMETER;
+ vol = get_ldnumber(&path);
+ if (vol < 0) return FR_INVALID_DRIVE;
+ fs = FatFs[vol];
+ if (!fs) return FR_NOT_ENABLED;
+ fs->fs_type = 0;
+ pdrv = LD2PD(vol); /* Physical drive */
+ part = LD2PT(vol); /* Partition (0:auto detect, 1-4:get from partition table)*/
+
+ /* Get disk statics */
+ stat = disk_initialize(pdrv);
+ if (stat & STA_NOINIT) return FR_NOT_READY;
+ if (stat & STA_PROTECT) return FR_WRITE_PROTECTED;
+#if _MAX_SS != _MIN_SS /* Get disk sector size */
+ if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK || SS(fs) > _MAX_SS || SS(fs) < _MIN_SS)
+ return FR_DISK_ERR;
+#endif
+ if (_MULTI_PARTITION && part) {
+ /* Get partition information from partition table in the MBR */
+ if (disk_read(pdrv, fs->win, 0, 1) != RES_OK) return FR_DISK_ERR;
+ if (LD_WORD(fs->win + BS_55AA) != 0xAA55) return FR_MKFS_ABORTED;
+ tbl = &fs->win[MBR_Table + (part - 1) * SZ_PTE];
+ if (!tbl[4]) return FR_MKFS_ABORTED; /* No partition? */
+ b_vol = LD_DWORD(tbl + 8); /* Volume start sector */
+ n_vol = LD_DWORD(tbl + 12); /* Volume size */
+ } else {
+ /* Create a partition in this function */
+ if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &n_vol) != RES_OK || n_vol < 128)
+ return FR_DISK_ERR;
+ b_vol = (sfd) ? 0 : 63; /* Volume start sector */
+ n_vol -= b_vol; /* Volume size */
+ }
+
+ if (au & (au - 1)) au = 0;
+ if (!au) { /* AU auto selection */
+ vs = n_vol / (2000 / (SS(fs) / 512));
+ for (i = 0; vs < vst[i]; i++) ;
+ au = cst[i];
+ }
+ if (au >= _MIN_SS) au /= SS(fs); /* Number of sectors per cluster */
+ if (!au) au = 1;
+ if (au > 128) au = 128;
+
+ /* Pre-compute number of clusters and FAT sub-type */
+ n_clst = n_vol / au;
+ fmt = FS_FAT12;
+ if (n_clst >= MIN_FAT16) fmt = FS_FAT16;
+ if (n_clst >= MIN_FAT32) fmt = FS_FAT32;
+
+ /* Determine offset and size of FAT structure */
+ if (fmt == FS_FAT32) {
+ n_fat = ((n_clst * 4) + 8 + SS(fs) - 1) / SS(fs);
+ n_rsv = 32;
+ n_dir = 0;
+ } else {
+ n_fat = (fmt == FS_FAT12) ? (n_clst * 3 + 1) / 2 + 3 : (n_clst * 2) + 4;
+ n_fat = (n_fat + SS(fs) - 1) / SS(fs);
+ n_rsv = 1;
+ n_dir = (DWORD)N_ROOTDIR * SZ_DIRE / SS(fs);
+ }
+ b_fat = b_vol + n_rsv; /* FAT area start sector */
+ b_dir = b_fat + n_fat * N_FATS; /* Directory area start sector */
+ b_data = b_dir + n_dir; /* Data area start sector */
+ if (n_vol < b_data + au - b_vol) return FR_MKFS_ABORTED; /* Too small volume */
+
+ /* Align data start sector to erase block boundary (for flash memory media) */
+ if (disk_ioctl(pdrv, GET_BLOCK_SIZE, &n) != RES_OK || !n || n > 32768) n = 1;
+ n = (b_data + n - 1) & ~(n - 1); /* Next nearest erase block from current data start */
+ n = (n - b_data) / N_FATS;
+ if (fmt == FS_FAT32) { /* FAT32: Move FAT offset */
+ n_rsv += n;
+ b_fat += n;
+ } else { /* FAT12/16: Expand FAT size */
+ n_fat += n;
+ }
+
+ /* Determine number of clusters and final check of validity of the FAT sub-type */
+ n_clst = (n_vol - n_rsv - n_fat * N_FATS - n_dir) / au;
+ if ( (fmt == FS_FAT16 && n_clst < MIN_FAT16)
+ || (fmt == FS_FAT32 && n_clst < MIN_FAT32))
+ return FR_MKFS_ABORTED;
+
+ /* Determine system ID in the partition table */
+ if (fmt == FS_FAT32) {
+ sys = 0x0C; /* FAT32X */
+ } else {
+ if (fmt == FS_FAT12 && n_vol < 0x10000) {
+ sys = 0x01; /* FAT12(<65536) */
+ } else {
+ sys = (n_vol < 0x10000) ? 0x04 : 0x06; /* FAT16(<65536) : FAT12/16(>=65536) */
+ }
+ }
+
+ if (_MULTI_PARTITION && part) {
+ /* Update system ID in the partition table */
+ tbl = &fs->win[MBR_Table + (part - 1) * SZ_PTE];
+ tbl[4] = sys;
+ if (disk_write(pdrv, fs->win, 0, 1) != RES_OK) /* Write it to teh MBR */
+ return FR_DISK_ERR;
+ md = 0xF8;
+ } else {
+ if (sfd) { /* No partition table (SFD) */
+ md = 0xF0;
+ } else { /* Create partition table (FDISK) */
+ mem_set(fs->win, 0, SS(fs));
+ tbl = fs->win + MBR_Table; /* Create partition table for single partition in the drive */
+ tbl[1] = 1; /* Partition start head */
+ tbl[2] = 1; /* Partition start sector */
+ tbl[3] = 0; /* Partition start cylinder */
+ tbl[4] = sys; /* System type */
+ tbl[5] = 254; /* Partition end head */
+ n = (b_vol + n_vol) / 63 / 255;
+ tbl[6] = (BYTE)(n >> 2 | 63); /* Partition end sector */
+ tbl[7] = (BYTE)n; /* End cylinder */
+ ST_DWORD(tbl + 8, 63); /* Partition start in LBA */
+ ST_DWORD(tbl + 12, n_vol); /* Partition size in LBA */
+ ST_WORD(fs->win + BS_55AA, 0xAA55); /* MBR signature */
+ if (disk_write(pdrv, fs->win, 0, 1) != RES_OK) /* Write it to the MBR */
+ return FR_DISK_ERR;
+ md = 0xF8;
+ }
+ }
+
+ /* Create BPB in the VBR */
+ tbl = fs->win; /* Clear sector */
+ mem_set(tbl, 0, SS(fs));
+ mem_cpy(tbl, "\xEB\xFE\x90" "MSDOS5.0", 11);/* Boot jump code, OEM name */
+ i = SS(fs); /* Sector size */
+ ST_WORD(tbl + BPB_BytsPerSec, i);
+ tbl[BPB_SecPerClus] = (BYTE)au; /* Sectors per cluster */
+ ST_WORD(tbl + BPB_RsvdSecCnt, n_rsv); /* Reserved sectors */
+ tbl[BPB_NumFATs] = N_FATS; /* Number of FATs */
+ i = (fmt == FS_FAT32) ? 0 : N_ROOTDIR; /* Number of root directory entries */
+ ST_WORD(tbl + BPB_RootEntCnt, i);
+ if (n_vol < 0x10000) { /* Number of total sectors */
+ ST_WORD(tbl + BPB_TotSec16, n_vol);
+ } else {
+ ST_DWORD(tbl + BPB_TotSec32, n_vol);
+ }
+ tbl[BPB_Media] = md; /* Media descriptor */
+ ST_WORD(tbl + BPB_SecPerTrk, 63); /* Number of sectors per track */
+ ST_WORD(tbl + BPB_NumHeads, 255); /* Number of heads */
+ ST_DWORD(tbl + BPB_HiddSec, b_vol); /* Hidden sectors */
+ n = GET_FATTIME(); /* Use current time as VSN */
+ if (fmt == FS_FAT32) {
+ ST_DWORD(tbl + BS_VolID32, n); /* VSN */
+ ST_DWORD(tbl + BPB_FATSz32, n_fat); /* Number of sectors per FAT */
+ ST_DWORD(tbl + BPB_RootClus, 2); /* Root directory start cluster (2) */
+ ST_WORD(tbl + BPB_FSInfo, 1); /* FSINFO record offset (VBR + 1) */
+ ST_WORD(tbl + BPB_BkBootSec, 6); /* Backup boot record offset (VBR + 6) */
+ tbl[BS_DrvNum32] = 0x80; /* Drive number */
+ tbl[BS_BootSig32] = 0x29; /* Extended boot signature */
+ mem_cpy(tbl + BS_VolLab32, "NO NAME " "FAT32 ", 19); /* Volume label, FAT signature */
+ } else {
+ ST_DWORD(tbl + BS_VolID, n); /* VSN */
+ ST_WORD(tbl + BPB_FATSz16, n_fat); /* Number of sectors per FAT */
+ tbl[BS_DrvNum] = 0x80; /* Drive number */
+ tbl[BS_BootSig] = 0x29; /* Extended boot signature */
+ mem_cpy(tbl + BS_VolLab, "NO NAME " "FAT ", 19); /* Volume label, FAT signature */
+ }
+ ST_WORD(tbl + BS_55AA, 0xAA55); /* Signature (Offset is fixed here regardless of sector size) */
+ if (disk_write(pdrv, tbl, b_vol, 1) != RES_OK) /* Write it to the VBR sector */
+ return FR_DISK_ERR;
+ if (fmt == FS_FAT32) /* Write backup VBR if needed (VBR + 6) */
+ disk_write(pdrv, tbl, b_vol + 6, 1);
+
+ /* Initialize FAT area */
+ wsect = b_fat;
+ for (i = 0; i < N_FATS; i++) { /* Initialize each FAT copy */
+ mem_set(tbl, 0, SS(fs)); /* 1st sector of the FAT */
+ n = md; /* Media descriptor byte */
+ if (fmt != FS_FAT32) {
+ n |= (fmt == FS_FAT12) ? 0x00FFFF00 : 0xFFFFFF00;
+ ST_DWORD(tbl + 0, n); /* Reserve cluster #0-1 (FAT12/16) */
+ } else {
+ n |= 0xFFFFFF00;
+ ST_DWORD(tbl + 0, n); /* Reserve cluster #0-1 (FAT32) */
+ ST_DWORD(tbl + 4, 0xFFFFFFFF);
+ ST_DWORD(tbl + 8, 0x0FFFFFFF); /* Reserve cluster #2 for root directory */
+ }
+ if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK)
+ return FR_DISK_ERR;
+ mem_set(tbl, 0, SS(fs)); /* Fill following FAT entries with zero */
+ for (n = 1; n < n_fat; n++) { /* This loop may take a time on FAT32 volume due to many single sector writes */
+ if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK)
+ return FR_DISK_ERR;
+ }
+ }
+
+ /* Initialize root directory */
+ i = (fmt == FS_FAT32) ? au : (UINT)n_dir;
+ do {
+ if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK)
+ return FR_DISK_ERR;
+ } while (--i);
+
+#if _USE_TRIM /* Erase data area if needed */
+ {
+ eb[0] = wsect; eb[1] = wsect + (n_clst - ((fmt == FS_FAT32) ? 1 : 0)) * au - 1;
+ disk_ioctl(pdrv, CTRL_TRIM, eb);
+ }
+#endif
+
+ /* Create FSINFO if needed */
+ if (fmt == FS_FAT32) {
+ ST_DWORD(tbl + FSI_LeadSig, 0x41615252);
+ ST_DWORD(tbl + FSI_StrucSig, 0x61417272);
+ ST_DWORD(tbl + FSI_Free_Count, n_clst - 1); /* Number of free clusters */
+ ST_DWORD(tbl + FSI_Nxt_Free, 2); /* Last allocated cluster# */
+ ST_WORD(tbl + BS_55AA, 0xAA55);
+ disk_write(pdrv, tbl, b_vol + 1, 1); /* Write original (VBR + 1) */
+ disk_write(pdrv, tbl, b_vol + 7, 1); /* Write backup (VBR + 7) */
+ }
+
+ return (disk_ioctl(pdrv, CTRL_SYNC, 0) == RES_OK) ? FR_OK : FR_DISK_ERR;
+}
+
+
+
+#if _MULTI_PARTITION
+/*-----------------------------------------------------------------------*/
+/* Create partition table on the physical drive */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_fdisk (
+ BYTE pdrv, /* Physical drive number */
+ const DWORD szt[], /* Pointer to the size table for each partitions */
+ void* work /* Pointer to the working buffer */
+)
+{
+ UINT i, n, sz_cyl, tot_cyl, b_cyl, e_cyl, p_cyl;
+ BYTE s_hd, e_hd, *p, *buf = (BYTE*)work;
+ DSTATUS stat;
+ DWORD sz_disk, sz_part, s_part;
+
+
+ stat = disk_initialize(pdrv);
+ if (stat & STA_NOINIT) return FR_NOT_READY;
+ if (stat & STA_PROTECT) return FR_WRITE_PROTECTED;
+ if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_disk)) return FR_DISK_ERR;
+
+ /* Determine CHS in the table regardless of the drive geometry */
+ for (n = 16; n < 256 && sz_disk / n / 63 > 1024; n *= 2) ;
+ if (n == 256) n--;
+ e_hd = n - 1;
+ sz_cyl = 63 * n;
+ tot_cyl = sz_disk / sz_cyl;
+
+ /* Create partition table */
+ mem_set(buf, 0, _MAX_SS);
+ p = buf + MBR_Table; b_cyl = 0;
+ for (i = 0; i < 4; i++, p += SZ_PTE) {
+ p_cyl = (szt[i] <= 100U) ? (DWORD)tot_cyl * szt[i] / 100 : szt[i] / sz_cyl;
+ if (!p_cyl) continue;
+ s_part = (DWORD)sz_cyl * b_cyl;
+ sz_part = (DWORD)sz_cyl * p_cyl;
+ if (i == 0) { /* Exclude first track of cylinder 0 */
+ s_hd = 1;
+ s_part += 63; sz_part -= 63;
+ } else {
+ s_hd = 0;
+ }
+ e_cyl = b_cyl + p_cyl - 1;
+ if (e_cyl >= tot_cyl) return FR_INVALID_PARAMETER;
+
+ /* Set partition table */
+ p[1] = s_hd; /* Start head */
+ p[2] = (BYTE)((b_cyl >> 2) + 1); /* Start sector */
+ p[3] = (BYTE)b_cyl; /* Start cylinder */
+ p[4] = 0x06; /* System type (temporary setting) */
+ p[5] = e_hd; /* End head */
+ p[6] = (BYTE)((e_cyl >> 2) + 63); /* End sector */
+ p[7] = (BYTE)e_cyl; /* End cylinder */
+ ST_DWORD(p + 8, s_part); /* Start sector in LBA */
+ ST_DWORD(p + 12, sz_part); /* Partition size */
+
+ /* Next partition */
+ b_cyl += p_cyl;
+ }
+ ST_WORD(p, 0xAA55);
+
+ /* Write it to the MBR */
+ return (disk_write(pdrv, buf, 0, 1) != RES_OK || disk_ioctl(pdrv, CTRL_SYNC, 0) != RES_OK) ? FR_DISK_ERR : FR_OK;
+}
+
+
+#endif /* _MULTI_PARTITION */
+#endif /* _USE_MKFS && !_FS_READONLY */
+
+
+
+
+#if _USE_STRFUNC
+/*-----------------------------------------------------------------------*/
+/* Get a string from the file */
+/*-----------------------------------------------------------------------*/
+
+TCHAR* f_gets (
+ TCHAR* buff, /* Pointer to the string buffer to read */
+ int len, /* Size of string buffer (characters) */
+ FIL* fp /* Pointer to the file object */
+)
+{
+ int n = 0;
+ TCHAR c, *p = buff;
+ BYTE s[2];
+ UINT rc;
+
+
+ while (n < len - 1) { /* Read characters until buffer gets filled */
+#if _USE_LFN && _LFN_UNICODE
+#if _STRF_ENCODE == 3 /* Read a character in UTF-8 */
+ f_read(fp, s, 1, &rc);
+ if (rc != 1) break;
+ c = s[0];
+ if (c >= 0x80) {
+ if (c < 0xC0) continue; /* Skip stray trailer */
+ if (c < 0xE0) { /* Two-byte sequence */
+ f_read(fp, s, 1, &rc);
+ if (rc != 1) break;
+ c = (c & 0x1F) << 6 | (s[0] & 0x3F);
+ if (c < 0x80) c = '?';
+ } else {
+ if (c < 0xF0) { /* Three-byte sequence */
+ f_read(fp, s, 2, &rc);
+ if (rc != 2) break;
+ c = c << 12 | (s[0] & 0x3F) << 6 | (s[1] & 0x3F);
+ if (c < 0x800) c = '?';
+ } else { /* Reject four-byte sequence */
+ c = '?';
+ }
+ }
+ }
+#elif _STRF_ENCODE == 2 /* Read a character in UTF-16BE */
+ f_read(fp, s, 2, &rc);
+ if (rc != 2) break;
+ c = s[1] + (s[0] << 8);
+#elif _STRF_ENCODE == 1 /* Read a character in UTF-16LE */
+ f_read(fp, s, 2, &rc);
+ if (rc != 2) break;
+ c = s[0] + (s[1] << 8);
+#else /* Read a character in ANSI/OEM */
+ f_read(fp, s, 1, &rc);
+ if (rc != 1) break;
+ c = s[0];
+ if (IsDBCS1(c)) {
+ f_read(fp, s, 1, &rc);
+ if (rc != 1) break;
+ c = (c << 8) + s[0];
+ }
+ c = ff_convert(c, 1); /* OEM -> Unicode */
+ if (!c) c = '?';
+#endif
+#else /* Read a character without conversion */
+ f_read(fp, s, 1, &rc);
+ if (rc != 1) break;
+ c = s[0];
+#endif
+ if (_USE_STRFUNC == 2 && c == '\r') continue; /* Strip '\r' */
+ *p++ = c;
+ n++;
+ if (c == '\n') break; /* Break on EOL */
+ }
+ *p = 0;
+ return n ? buff : 0; /* When no data read (eof or error), return with error. */
+}
+
+
+
+
+#if !_FS_READONLY
+#include <stdarg.h>
+/*-----------------------------------------------------------------------*/
+/* Put a character to the file */
+/*-----------------------------------------------------------------------*/
+
+typedef struct {
+ FIL* fp;
+ int idx, nchr;
+ BYTE buf[64];
+} putbuff;
+
+
+static
+void putc_bfd (
+ putbuff* pb,
+ TCHAR c
+)
+{
+ UINT bw;
+ int i;
+
+
+ if (_USE_STRFUNC == 2 && c == '\n') /* LF -> CRLF conversion */
+ putc_bfd(pb, '\r');
+
+ i = pb->idx; /* Buffer write index (-1:error) */
+ if (i < 0) return;
+
+#if _USE_LFN && _LFN_UNICODE
+#if _STRF_ENCODE == 3 /* Write a character in UTF-8 */
+ if (c < 0x80) { /* 7-bit */
+ pb->buf[i++] = (BYTE)c;
+ } else {
+ if (c < 0x800) { /* 11-bit */
+ pb->buf[i++] = (BYTE)(0xC0 | c >> 6);
+ } else { /* 16-bit */
+ pb->buf[i++] = (BYTE)(0xE0 | c >> 12);
+ pb->buf[i++] = (BYTE)(0x80 | (c >> 6 & 0x3F));
+ }
+ pb->buf[i++] = (BYTE)(0x80 | (c & 0x3F));
+ }
+#elif _STRF_ENCODE == 2 /* Write a character in UTF-16BE */
+ pb->buf[i++] = (BYTE)(c >> 8);
+ pb->buf[i++] = (BYTE)c;
+#elif _STRF_ENCODE == 1 /* Write a character in UTF-16LE */
+ pb->buf[i++] = (BYTE)c;
+ pb->buf[i++] = (BYTE)(c >> 8);
+#else /* Write a character in ANSI/OEM */
+ c = ff_convert(c, 0); /* Unicode -> OEM */
+ if (!c) c = '?';
+ if (c >= 0x100)
+ pb->buf[i++] = (BYTE)(c >> 8);
+ pb->buf[i++] = (BYTE)c;
+#endif
+#else /* Write a character without conversion */
+ pb->buf[i++] = (BYTE)c;
+#endif
+
+ if (i >= (int)(sizeof pb->buf) - 3) { /* Write buffered characters to the file */
+ f_write(pb->fp, pb->buf, (UINT)i, &bw);
+ i = (bw == (UINT)i) ? 0 : -1;
+ }
+ pb->idx = i;
+ pb->nchr++;
+}
+
+
+
+int f_putc (
+ TCHAR c, /* A character to be output */
+ FIL* fp /* Pointer to the file object */
+)
+{
+ putbuff pb;
+ UINT nw;
+
+
+ pb.fp = fp; /* Initialize output buffer */
+ pb.nchr = pb.idx = 0;
+
+ putc_bfd(&pb, c); /* Put a character */
+
+ if ( pb.idx >= 0 /* Flush buffered characters to the file */
+ && f_write(pb.fp, pb.buf, (UINT)pb.idx, &nw) == FR_OK
+ && (UINT)pb.idx == nw) return pb.nchr;
+ return EOF;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Put a string to the file */
+/*-----------------------------------------------------------------------*/
+
+int f_puts (
+ const TCHAR* str, /* Pointer to the string to be output */
+ FIL* fp /* Pointer to the file object */
+)
+{
+ putbuff pb;
+ UINT nw;
+
+
+ pb.fp = fp; /* Initialize output buffer */
+ pb.nchr = pb.idx = 0;
+
+ while (*str) /* Put the string */
+ putc_bfd(&pb, *str++);
+
+ if ( pb.idx >= 0 /* Flush buffered characters to the file */
+ && f_write(pb.fp, pb.buf, (UINT)pb.idx, &nw) == FR_OK
+ && (UINT)pb.idx == nw) return pb.nchr;
+ return EOF;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Put a formatted string to the file */
+/*-----------------------------------------------------------------------*/
+
+int f_printf (
+ FIL* fp, /* Pointer to the file object */
+ const TCHAR* fmt, /* Pointer to the format string */
+ ... /* Optional arguments... */
+)
+{
+ va_list arp;
+ BYTE f, r;
+ UINT nw, i, j, w;
+ DWORD v;
+ TCHAR c, d, s[16], *p;
+ putbuff pb;
+
+
+ pb.fp = fp; /* Initialize output buffer */
+ pb.nchr = pb.idx = 0;
+
+ va_start(arp, fmt);
+
+ for (;;) {
+ c = *fmt++;
+ if (c == 0) break; /* End of string */
+ if (c != '%') { /* Non escape character */
+ putc_bfd(&pb, c);
+ continue;
+ }
+ w = f = 0;
+ c = *fmt++;
+ if (c == '0') { /* Flag: '0' padding */
+ f = 1; c = *fmt++;
+ } else {
+ if (c == '-') { /* Flag: left justified */
+ f = 2; c = *fmt++;
+ }
+ }
+ while (IsDigit(c)) { /* Precision */
+ w = w * 10 + c - '0';
+ c = *fmt++;
+ }
+ if (c == 'l' || c == 'L') { /* Prefix: Size is long int */
+ f |= 4; c = *fmt++;
+ }
+ if (!c) break;
+ d = c;
+ if (IsLower(d)) d -= 0x20;
+ switch (d) { /* Type is... */
+ case 'S' : /* String */
+ p = va_arg(arp, TCHAR*);
+ for (j = 0; p[j]; j++) ;
+ if (!(f & 2)) {
+ while (j++ < w) putc_bfd(&pb, ' ');
+ }
+ while (*p) putc_bfd(&pb, *p++);
+ while (j++ < w) putc_bfd(&pb, ' ');
+ continue;
+ case 'C' : /* Character */
+ putc_bfd(&pb, (TCHAR)va_arg(arp, int)); continue;
+ case 'B' : /* Binary */
+ r = 2; break;
+ case 'O' : /* Octal */
+ r = 8; break;
+ case 'D' : /* Signed decimal */
+ case 'U' : /* Unsigned decimal */
+ r = 10; break;
+ case 'X' : /* Hexdecimal */
+ r = 16; break;
+ default: /* Unknown type (pass-through) */
+ putc_bfd(&pb, c); continue;
+ }
+
+ /* Get an argument and put it in numeral */
+ v = (f & 4) ? (DWORD)va_arg(arp, long) : ((d == 'D') ? (DWORD)(long)va_arg(arp, int) : (DWORD)va_arg(arp, unsigned int));
+ if (d == 'D' && (v & 0x80000000)) {
+ v = 0 - v;
+ f |= 8;
+ }
+ i = 0;
+ do {
+ d = (TCHAR)(v % r); v /= r;
+ if (d > 9) d += (c == 'x') ? 0x27 : 0x07;
+ s[i++] = d + '0';
+ } while (v && i < sizeof s / sizeof s[0]);
+ if (f & 8) s[i++] = '-';
+ j = i; d = (f & 1) ? '0' : ' ';
+ while (!(f & 2) && j++ < w) putc_bfd(&pb, d);
+ do putc_bfd(&pb, s[--i]); while (i);
+ while (j++ < w) putc_bfd(&pb, d);
+ }
+
+ va_end(arp);
+
+ if ( pb.idx >= 0 /* Flush buffered characters to the file */
+ && f_write(pb.fp, pb.buf, (UINT)pb.idx, &nw) == FR_OK
+ && (UINT)pb.idx == nw) return pb.nchr;
+ return EOF;
+}
+
+#endif /* !_FS_READONLY */
+#endif /* _USE_STRFUNC */
diff --git a/emb/pastilda/fs/fatfs/ff.h b/emb/pastilda/fs/fatfs/ff.h
new file mode 100644
index 0000000..bd63d3f
--- /dev/null
+++ b/emb/pastilda/fs/fatfs/ff.h
@@ -0,0 +1,342 @@
+/*---------------------------------------------------------------------------/
+/ FatFs - FAT file system module include R0.11 (C)ChaN, 2015
+/----------------------------------------------------------------------------/
+/ FatFs module is a free software that opened under license policy of
+/ following conditions.
+/
+/ Copyright (C) 2015, ChaN, all right reserved.
+/
+/ 1. Redistributions of source code must retain the above copyright notice,
+/ this condition and the following disclaimer.
+/
+/ This software is provided by the copyright holder and contributors "AS IS"
+/ and any warranties related to this software are DISCLAIMED.
+/ The copyright owner or contributors be NOT LIABLE for any damages caused
+/ by use of this software.
+/---------------------------------------------------------------------------*/
+
+
+#ifndef _FATFS
+#define _FATFS 32020 /* Revision ID */
+
+#include <fs/fatfs/ffconf.h> /* FatFs configuration options */
+#include <fs/fatfs/integer.h> /* Basic integer types */
+#if _FATFS != _FFCONF
+#error Wrong configuration file (ffconf.h).
+#endif
+
+
+
+/* Definitions of volume management */
+
+#if _MULTI_PARTITION /* Multiple partition configuration */
+typedef struct {
+ BYTE pd; /* Physical drive number */
+ BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */
+} PARTITION;
+extern PARTITION VolToPart[]; /* Volume - Partition resolution table */
+#define LD2PD(vol) (VolToPart[vol].pd) /* Get physical drive number */
+#define LD2PT(vol) (VolToPart[vol].pt) /* Get partition index */
+
+#else /* Single partition configuration */
+#define LD2PD(vol) (BYTE)(vol) /* Each logical drive is bound to the same physical drive number */
+#define LD2PT(vol) 0 /* Find first valid partition or in SFD */
+
+#endif
+
+
+
+/* Type of path name strings on FatFs API */
+
+#if _LFN_UNICODE /* Unicode string */
+#if !_USE_LFN
+#error _LFN_UNICODE must be 0 at non-LFN cfg.
+#endif
+#ifndef _INC_TCHAR
+typedef WCHAR TCHAR;
+#define _T(x) L ## x
+#define _TEXT(x) L ## x
+#endif
+
+#else /* ANSI/OEM string */
+#ifndef _INC_TCHAR
+typedef char TCHAR;
+#define _T(x) x
+#define _TEXT(x) x
+#endif
+
+#endif
+
+
+
+/* File system object structure (FATFS) */
+
+typedef struct {
+ BYTE fs_type; /* FAT sub-type (0:Not mounted) */
+ BYTE drv; /* Physical drive number */
+ BYTE csize; /* Sectors per cluster (1,2,4...128) */
+ BYTE n_fats; /* Number of FAT copies (1 or 2) */
+ BYTE wflag; /* win[] flag (b0:dirty) */
+ BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */
+ WORD id; /* File system mount ID */
+ WORD n_rootdir; /* Number of root directory entries (FAT12/16) */
+#if _MAX_SS != _MIN_SS
+ WORD ssize; /* Bytes per sector (512, 1024, 2048 or 4096) */
+#endif
+#if _FS_REENTRANT
+ _SYNC_t sobj; /* Identifier of sync object */
+#endif
+#if !_FS_READONLY
+ DWORD last_clust; /* Last allocated cluster */
+ DWORD free_clust; /* Number of free clusters */
+#endif
+#if _FS_RPATH
+ DWORD cdir; /* Current directory start cluster (0:root) */
+#endif
+ DWORD n_fatent; /* Number of FAT entries, = number of clusters + 2 */
+ DWORD fsize; /* Sectors per FAT */
+ DWORD volbase; /* Volume start sector */
+ DWORD fatbase; /* FAT start sector */
+ DWORD dirbase; /* Root directory start sector (FAT32:Cluster#) */
+ DWORD database; /* Data start sector */
+ DWORD winsect; /* Current sector appearing in the win[] */
+ BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */
+} FATFS;
+
+
+
+/* File object structure (FIL) */
+
+typedef struct {
+ FATFS* fs; /* Pointer to the related file system object (**do not change order**) */
+ WORD id; /* Owner file system mount ID (**do not change order**) */
+ BYTE flag; /* Status flags */
+ BYTE err; /* Abort flag (error code) */
+ DWORD fptr; /* File read/write pointer (Zeroed on file open) */
+ DWORD fsize; /* File size */
+ DWORD sclust; /* File start cluster (0:no cluster chain, always 0 when fsize is 0) */
+ DWORD clust; /* Current cluster of fpter (not valid when fprt is 0) */
+ DWORD dsect; /* Sector number appearing in buf[] (0:invalid) */
+#if !_FS_READONLY
+ DWORD dir_sect; /* Sector number containing the directory entry */
+ BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */
+#endif
+#if _USE_FASTSEEK
+ DWORD* cltbl; /* Pointer to the cluster link map table (Nulled on file open) */
+#endif
+#if _FS_LOCK
+ UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */
+#endif
+#if !_FS_TINY
+ BYTE buf[_MAX_SS]; /* File private data read/write window */
+#endif
+} FIL;
+
+
+
+/* Directory object structure (DIR) */
+
+typedef struct {
+ FATFS* fs; /* Pointer to the owner file system object (**do not change order**) */
+ WORD id; /* Owner file system mount ID (**do not change order**) */
+ WORD index; /* Current read/write index number */
+ DWORD sclust; /* Table start cluster (0:Root dir) */
+ DWORD clust; /* Current cluster */
+ DWORD sect; /* Current sector */
+ BYTE* dir; /* Pointer to the current SFN entry in the win[] */
+ BYTE* fn; /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */
+#if _FS_LOCK
+ UINT lockid; /* File lock ID (index of file semaphore table Files[]) */
+#endif
+#if _USE_LFN
+ WCHAR* lfn; /* Pointer to the LFN working buffer */
+ WORD lfn_idx; /* Last matched LFN index number (0xFFFF:No LFN) */
+#endif
+#if _USE_FIND
+ const TCHAR* pat; /* Pointer to the name matching pattern */
+#endif
+} DIR;
+
+
+
+/* File information structure (FILINFO) */
+
+typedef struct {
+ DWORD fsize; /* File size */
+ WORD fdate; /* Last modified date */
+ WORD ftime; /* Last modified time */
+ BYTE fattrib; /* Attribute */
+ TCHAR fname[13]; /* Short file name (8.3 format) */
+#if _USE_LFN
+ TCHAR* lfname; /* Pointer to the LFN buffer */
+ UINT lfsize; /* Size of LFN buffer in TCHAR */
+#endif
+} FILINFO;
+
+
+
+/* File function return code (FRESULT) */
+
+typedef enum {
+ FR_OK = 0, /* (0) Succeeded */
+ FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */
+ FR_INT_ERR, /* (2) Assertion failed */
+ FR_NOT_READY, /* (3) The physical drive cannot work */
+ FR_NO_FILE, /* (4) Could not find the file */
+ FR_NO_PATH, /* (5) Could not find the path */
+ FR_INVALID_NAME, /* (6) The path name format is invalid */
+ FR_DENIED, /* (7) Access denied due to prohibited access or directory full */
+ FR_EXIST, /* (8) Access denied due to prohibited access */
+ FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */
+ FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */
+ FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */
+ FR_NOT_ENABLED, /* (12) The volume has no work area */
+ FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */
+ FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any parameter error */
+ FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
+ FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
+ FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
+ FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_SHARE */
+ FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
+} FRESULT;
+
+
+
+/*--------------------------------------------------------------*/
+/* FatFs module application interface */
+
+FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */
+FRESULT f_close (FIL* fp); /* Close an open file object */
+FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from a file */
+FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to a file */
+FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
+FRESULT f_lseek (FIL* fp, DWORD ofs); /* Move file pointer of a file object */
+FRESULT f_truncate (FIL* fp); /* Truncate file */
+FRESULT f_sync (FIL* fp); /* Flush cached data of a writing file */
+FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */
+FRESULT f_closedir (DIR* dp); /* Close an open directory */
+FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */
+FRESULT f_findfirst (DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */
+FRESULT f_findnext (DIR* dp, FILINFO* fno); /* Find next file */
+FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */
+FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */
+FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */
+FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */
+FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of the file/dir */
+FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change times-tamp of the file/dir */
+FRESULT f_chdir (const TCHAR* path); /* Change current directory */
+FRESULT f_chdrive (const TCHAR* path); /* Change current drive */
+FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */
+FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */
+FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */
+FRESULT f_setlabel (const TCHAR* label); /* Set volume label */
+FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
+FRESULT f_mkfs (const TCHAR* path, BYTE sfd, UINT au); /* Create a file system on the volume */
+FRESULT f_fdisk (BYTE pdrv, const DWORD szt[], void* work); /* Divide a physical drive into some partitions */
+int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */
+int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */
+int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */
+TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */
+
+#define f_eof(fp) ((int)((fp)->fptr == (fp)->fsize))
+#define f_error(fp) ((fp)->err)
+#define f_tell(fp) ((fp)->fptr)
+#define f_size(fp) ((fp)->fsize)
+#define f_rewind(fp) f_lseek((fp), 0)
+#define f_rewinddir(dp) f_readdir((dp), 0)
+
+#ifndef EOF
+#define EOF (-1)
+#endif
+
+
+
+
+/*--------------------------------------------------------------*/
+/* Additional user defined functions */
+
+/* RTC function */
+#if !_FS_READONLY && !_FS_NORTC
+DWORD get_fattime (void);
+#endif
+
+/* Unicode support functions */
+#if _USE_LFN /* Unicode - OEM code conversion */
+WCHAR ff_convert (WCHAR chr, UINT dir); /* OEM-Unicode bidirectional conversion */
+WCHAR ff_wtoupper (WCHAR chr); /* Unicode upper-case conversion */
+#if _USE_LFN == 3 /* Memory functions */
+void* ff_memalloc (UINT msize); /* Allocate memory block */
+void ff_memfree (void* mblock); /* Free memory block */
+#endif
+#endif
+
+/* Sync functions */
+#if _FS_REENTRANT
+int ff_cre_syncobj (BYTE vol, _SYNC_t* sobj); /* Create a sync object */
+int ff_req_grant (_SYNC_t sobj); /* Lock sync object */
+void ff_rel_grant (_SYNC_t sobj); /* Unlock sync object */
+int ff_del_syncobj (_SYNC_t sobj); /* Delete a sync object */
+#endif
+
+
+
+
+/*--------------------------------------------------------------*/
+/* Flags and offset address */
+
+
+/* File access control and file status flags (FIL.flag) */
+
+#define FA_READ 0x01
+#define FA_OPEN_EXISTING 0x00
+
+#if !_FS_READONLY
+#define FA_WRITE 0x02
+#define FA_CREATE_NEW 0x04
+#define FA_CREATE_ALWAYS 0x08
+#define FA_OPEN_ALWAYS 0x10
+#define FA__WRITTEN 0x20
+#define FA__DIRTY 0x40
+#endif
+
+
+/* FAT sub type (FATFS.fs_type) */
+
+#define FS_FAT12 1
+#define FS_FAT16 2
+#define FS_FAT32 3
+
+
+/* File attribute bits for directory entry */
+
+#define AM_RDO 0x01 /* Read only */
+#define AM_HID 0x02 /* Hidden */
+#define AM_SYS 0x04 /* System */
+#define AM_VOL 0x08 /* Volume label */
+#define AM_LFN 0x0F /* LFN entry */
+#define AM_DIR 0x10 /* Directory */
+#define AM_ARC 0x20 /* Archive */
+#define AM_MASK 0x3F /* Mask of defined bits */
+
+
+/* Fast seek feature */
+#define CREATE_LINKMAP 0xFFFFFFFF
+
+
+
+/*--------------------------------*/
+/* Multi-byte word access macros */
+
+#if _WORD_ACCESS == 1 /* Enable word access to the FAT structure */
+#define LD_WORD(ptr) (WORD)(*(WORD*)(BYTE*)(ptr))
+#define LD_DWORD(ptr) (DWORD)(*(DWORD*)(BYTE*)(ptr))
+#define ST_WORD(ptr,val) *(WORD*)(BYTE*)(ptr)=(WORD)(val)
+#define ST_DWORD(ptr,val) *(DWORD*)(BYTE*)(ptr)=(DWORD)(val)
+#else /* Use byte-by-byte access to the FAT structure */
+#define LD_WORD(ptr) (WORD)(((WORD)*((BYTE*)(ptr)+1)<<8)|(WORD)*(BYTE*)(ptr))
+#define LD_DWORD(ptr) (DWORD)(((DWORD)*((BYTE*)(ptr)+3)<<24)|((DWORD)*((BYTE*)(ptr)+2)<<16)|((WORD)*((BYTE*)(ptr)+1)<<8)|*(BYTE*)(ptr))
+#define ST_WORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8)
+#define ST_DWORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8); *((BYTE*)(ptr)+2)=(BYTE)((DWORD)(val)>>16); *((BYTE*)(ptr)+3)=(BYTE)((DWORD)(val)>>24)
+#endif
+
+#endif /* _FATFS */
diff --git a/emb/pastilda/fs/fatfs/ffconf.h b/emb/pastilda/fs/fatfs/ffconf.h
new file mode 100644
index 0000000..1df2a05
--- /dev/null
+++ b/emb/pastilda/fs/fatfs/ffconf.h
@@ -0,0 +1,271 @@
+/*---------------------------------------------------------------------------/
+/ FatFs - FAT file system module configuration file R0.11 (C)ChaN, 2015
+/---------------------------------------------------------------------------*/
+
+#define _FFCONF 32020 /* Revision ID */
+
+/*---------------------------------------------------------------------------/
+/ Functions and Buffer Configurations
+/---------------------------------------------------------------------------*/
+
+#define _FS_TINY 0
+/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
+/ At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS
+/ bytes. Instead of private sector buffer eliminated from the file object,
+/ common sector buffer in the file system object (FATFS) is used for the file
+/ data transfer. */
+
+
+#define _FS_READONLY 0
+/* This option switches read-only configuration. (0:Read/Write or 1:Read-only)
+/ Read-only configuration removes writing API functions, f_write(), f_sync(),
+/ f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree()
+/ and optional writing functions as well. */
+
+
+#define _FS_MINIMIZE 0
+/* This option defines minimization level to remove some basic API functions.
+/
+/ 0: All basic functions are enabled.
+/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_chmod(), f_utime(),
+/ f_truncate() and f_rename() function are removed.
+/ 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1.
+/ 3: f_lseek() function is removed in addition to 2. */
+
+
+#define _USE_STRFUNC 1
+/* This option switches string functions, f_gets(), f_putc(), f_puts() and
+/ f_printf().
+/
+/ 0: Disable string functions.
+/ 1: Enable without LF-CRLF conversion.
+/ 2: Enable with LF-CRLF conversion. */
+
+
+#define _USE_FIND 0
+/* This option switches filtered directory read feature and related functions,
+/ f_findfirst() and f_findnext(). (0:Disable or 1:Enable) */
+
+
+#define _USE_MKFS 1
+/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */
+
+
+#define _USE_FASTSEEK 0
+/* This option switches fast seek feature. (0:Disable or 1:Enable) */
+
+
+#define _USE_LABEL 0
+/* This option switches volume label functions, f_getlabel() and f_setlabel().
+/ (0:Disable or 1:Enable) */
+
+
+#define _USE_FORWARD 0
+/* This option switches f_forward() function. (0:Disable or 1:Enable)
+/ To enable it, also _FS_TINY need to be set to 1. */
+
+
+/*---------------------------------------------------------------------------/
+/ Locale and Namespace Configurations
+/---------------------------------------------------------------------------*/
+
+#define _CODE_PAGE 1
+/* This option specifies the OEM code page to be used on the target system.
+/ Incorrect setting of the code page can cause a file open failure.
+/
+/ 1 - ASCII (No extended character. Non-LFN cfg. only)
+/ 437 - U.S.
+/ 720 - Arabic
+/ 737 - Greek
+/ 775 - Baltic
+/ 850 - Multilingual Latin 1
+/ 852 - Latin 2
+/ 855 - Cyrillic
+/ 857 - Turkish
+/ 858 - Multilingual Latin 1 + Euro
+/ 862 - Hebrew
+/ 866 - Russian
+/ 874 - Thai
+/ 932 - Japanese Shift_JIS (DBCS)
+/ 936 - Simplified Chinese GBK (DBCS)
+/ 949 - Korean (DBCS)
+/ 950 - Traditional Chinese Big5 (DBCS)
+*/
+
+
+#define _USE_LFN 0
+#define _MAX_LFN 255
+/* The _USE_LFN option switches the LFN feature.
+/
+/ 0: Disable LFN feature. _MAX_LFN has no effect.
+/ 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe.
+/ 2: Enable LFN with dynamic working buffer on the STACK.
+/ 3: Enable LFN with dynamic working buffer on the HEAP.
+/
+/ When enable the LFN feature, Unicode handling functions (option/unicode.c) must
+/ be added to the project. The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes.
+/ When use stack for the working buffer, take care on stack overflow. When use heap
+/ memory for the working buffer, memory management functions, ff_memalloc() and
+/ ff_memfree(), must be added to the project. */
+
+
+#define _LFN_UNICODE 0
+/* This option switches character encoding on the API. (0:ANSI/OEM or 1:Unicode)
+/ To use Unicode string for the path name, enable LFN feature and set _LFN_UNICODE
+/ to 1. This option also affects behavior of string I/O functions. */
+
+
+#define _STRF_ENCODE 3
+/* When _LFN_UNICODE is 1, this option selects the character encoding on the file to
+/ be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf().
+/
+/ 0: ANSI/OEM
+/ 1: UTF-16LE
+/ 2: UTF-16BE
+/ 3: UTF-8
+/
+/ When _LFN_UNICODE is 0, this option has no effect. */
+
+
+#define _FS_RPATH 0
+/* This option configures relative path feature.
+/
+/ 0: Disable relative path feature and remove related functions.
+/ 1: Enable relative path feature. f_chdir() and f_chdrive() are available.
+/ 2: f_getcwd() function is available in addition to 1.
+/
+/ Note that directory items read via f_readdir() are affected by this option. */
+
+
+/*---------------------------------------------------------------------------/
+/ Drive/Volume Configurations
+/---------------------------------------------------------------------------*/
+
+#define _VOLUMES 1
+/* Number of volumes (logical drives) to be used. */
+
+
+#define _STR_VOLUME_ID 0
+#define _VOLUME_STRS "RAM","NAND","CF","SD1","SD2","USB1","USB2","USB3"
+/* _STR_VOLUME_ID option switches string volume ID feature.
+/ When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive
+/ number in the path name. _VOLUME_STRS defines the drive ID strings for each
+/ logical drives. Number of items must be equal to _VOLUMES. Valid characters for
+/ the drive ID strings are: A-Z and 0-9. */
+
+
+#define _MULTI_PARTITION 0
+/* This option switches multi-partition feature. By default (0), each logical drive
+/ number is bound to the same physical drive number and only an FAT volume found on
+/ the physical drive will be mounted. When multi-partition feature is enabled (1),
+/ each logical drive number is bound to arbitrary physical drive and partition
+/ listed in the VolToPart[]. Also f_fdisk() funciton will be available. */
+
+
+#define _MIN_SS 512
+#define _MAX_SS 512
+/* These options configure the range of sector size to be supported. (512, 1024,
+/ 2048 or 4096) Always set both 512 for most systems, all type of memory cards and
+/ harddisk. But a larger value may be required for on-board flash memory and some
+/ type of optical media. When _MAX_SS is larger than _MIN_SS, FatFs is configured
+/ to variable sector size and GET_SECTOR_SIZE command must be implemented to the
+/ disk_ioctl() function. */
+
+
+#define _USE_TRIM 0
+/* This option switches ATA-TRIM feature. (0:Disable or 1:Enable)
+/ To enable Trim feature, also CTRL_TRIM command should be implemented to the
+/ disk_ioctl() function. */
+
+
+#define _FS_NOFSINFO 0
+/* If you need to know correct free space on the FAT32 volume, set bit 0 of this
+/ option, and f_getfree() function at first time after volume mount will force
+/ a full FAT scan. Bit 1 controls the use of last allocated cluster number.
+/
+/ bit0=0: Use free cluster count in the FSINFO if available.
+/ bit0=1: Do not trust free cluster count in the FSINFO.
+/ bit1=0: Use last allocated cluster number in the FSINFO if available.
+/ bit1=1: Do not trust last allocated cluster number in the FSINFO.
+*/
+
+
+
+/*---------------------------------------------------------------------------/
+/ System Configurations
+/---------------------------------------------------------------------------*/
+
+#define _FS_NORTC 0
+#define _NORTC_MON 2
+#define _NORTC_MDAY 1
+#define _NORTC_YEAR 2015
+/* The _FS_NORTC option switches timestamp feature. If the system does not have
+/ an RTC function or valid timestamp is not needed, set _FS_NORTC to 1 to disable
+/ the timestamp feature. All objects modified by FatFs will have a fixed timestamp
+/ defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR.
+/ When timestamp feature is enabled (_FS_NORTC == 0), get_fattime() function need
+/ to be added to the project to read current time form RTC. _NORTC_MON,
+/ _NORTC_MDAY and _NORTC_YEAR have no effect.
+/ These options have no effect at read-only configuration (_FS_READONLY == 1). */
+
+
+#define _FS_LOCK 0
+/* The _FS_LOCK option switches file lock feature to control duplicated file open
+/ and illegal operation to open objects. This option must be 0 when _FS_READONLY
+/ is 1.
+/
+/ 0: Disable file lock feature. To avoid volume corruption, application program
+/ should avoid illegal open, remove and rename to the open objects.
+/ >0: Enable file lock feature. The value defines how many files/sub-directories
+/ can be opened simultaneously under file lock control. Note that the file
+/ lock feature is independent of re-entrancy. */
+
+
+#define _FS_REENTRANT 0
+#define _FS_TIMEOUT 1000
+#define _SYNC_t HANDLE
+/* The _FS_REENTRANT option switches the re-entrancy (thread safe) of the FatFs
+/ module itself. Note that regardless of this option, file access to different
+/ volume is always re-entrant and volume control functions, f_mount(), f_mkfs()
+/ and f_fdisk() function, are always not re-entrant. Only file/directory access
+/ to the same volume is under control of this feature.
+/
+/ 0: Disable re-entrancy. _FS_TIMEOUT and _SYNC_t have no effect.
+/ 1: Enable re-entrancy. Also user provided synchronization handlers,
+/ ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj()
+/ function, must be added to the project. Samples are available in
+/ option/syscall.c.
+/
+/ The _FS_TIMEOUT defines timeout period in unit of time tick.
+/ The _SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*,
+/ SemaphoreHandle_t and etc.. A header file for O/S definitions needs to be
+/ included somewhere in the scope of ff.c. */
+
+
+#define _WORD_ACCESS 0
+/* The _WORD_ACCESS option is an only platform dependent option. It defines
+/ which access method is used to the word data on the FAT volume.
+/
+/ 0: Byte-by-byte access. Always compatible with all platforms.
+/ 1: Word access. Do not choose this unless under both the following conditions.
+/
+/ * Address misaligned memory access is always allowed to ALL instructions.
+/ * Byte order on the memory is little-endian.
+/
+/ If it is the case, _WORD_ACCESS can also be set to 1 to reduce code size.
+/ Following table shows allowable settings of some processor types.
+/
+/ ARM7TDMI 0 *2 ColdFire 0 *1 V850E 0 *2
+/ Cortex-M3 0 *3 Z80 0/1 V850ES 0/1
+/ Cortex-M0 0 *2 x86 0/1 TLCS-870 0/1
+/ AVR 0/1 RX600(LE) 0/1 TLCS-900 0/1
+/ AVR32 0 *1 RL78 0 *2 R32C 0 *2
+/ PIC18 0/1 SH-2 0 *1 M16C 0/1
+/ PIC24 0 *2 H8S 0 *1 MSP430 0 *2
+/ PIC32 0 *1 H8/300H 0 *1 8051 0/1
+/
+/ *1:Big-endian.
+/ *2:Unaligned memory access is not supported.
+/ *3:Some compilers generate LDM/STM for mem_cpy function.
+*/
+
diff --git a/emb/pastilda/fs/fatfs/integer.h b/emb/pastilda/fs/fatfs/integer.h
new file mode 100644
index 0000000..f254b2a
--- /dev/null
+++ b/emb/pastilda/fs/fatfs/integer.h
@@ -0,0 +1,33 @@
+/*-------------------------------------------*/
+/* Integer type definitions for FatFs module */
+/*-------------------------------------------*/
+
+#ifndef _FF_INTEGER
+#define _FF_INTEGER
+
+#ifdef _WIN32 /* FatFs development platform */
+
+#include <windows.h>
+#include <tchar.h>
+
+#else /* Embedded platform */
+
+/* This type MUST be 8 bit */
+typedef unsigned char BYTE;
+
+/* These types MUST be 16 bit */
+typedef short SHORT;
+typedef unsigned short WORD;
+typedef unsigned short WCHAR;
+
+/* These types MUST be 16 bit or 32 bit */
+typedef int INT;
+typedef unsigned int UINT;
+
+/* These types MUST be 32 bit */
+typedef long LONG;
+typedef unsigned long DWORD;
+
+#endif
+
+#endif
diff --git a/emb/pastilda/fs/fatfs/option/syscall.c b/emb/pastilda/fs/fatfs/option/syscall.c
new file mode 100644
index 0000000..d9ad261
--- /dev/null
+++ b/emb/pastilda/fs/fatfs/option/syscall.c
@@ -0,0 +1,151 @@
+/*------------------------------------------------------------------------*/
+/* Sample code of OS dependent controls for FatFs */
+/* (C)ChaN, 2014 */
+/*------------------------------------------------------------------------*/
+
+
+#include <fs/fatfs/ff.h>
+
+
+#if _FS_REENTRANT
+/*------------------------------------------------------------------------*/
+/* Create a Synchronization Object
+/*------------------------------------------------------------------------*/
+/* This function is called in f_mount() function to create a new
+/ synchronization object, such as semaphore and mutex. When a 0 is returned,
+/ the f_mount() function fails with FR_INT_ERR.
+*/
+
+int ff_cre_syncobj ( /* !=0:Function succeeded, ==0:Could not create due to any error */
+ BYTE vol, /* Corresponding logical drive being processed */
+ _SYNC_t *sobj /* Pointer to return the created sync object */
+)
+{
+ int ret;
+
+
+ *sobj = CreateMutex(NULL, FALSE, NULL); /* Win32 */
+ ret = (int)(*sobj != INVALID_HANDLE_VALUE);
+
+// *sobj = SyncObjects[vol]; /* uITRON (give a static created sync object) */
+// ret = 1; /* The initial value of the semaphore must be 1. */
+
+// *sobj = OSMutexCreate(0, &err); /* uC/OS-II */
+// ret = (int)(err == OS_NO_ERR);
+
+// *sobj = xSemaphoreCreateMutex(); /* FreeRTOS */
+// ret = (int)(*sobj != NULL);
+
+ return ret;
+}
+
+
+
+/*------------------------------------------------------------------------*/
+/* Delete a Synchronization Object */
+/*------------------------------------------------------------------------*/
+/* This function is called in f_mount() function to delete a synchronization
+/ object that created with ff_cre_syncobj function. When a 0 is returned,
+/ the f_mount() function fails with FR_INT_ERR.
+*/
+
+int ff_del_syncobj ( /* !=0:Function succeeded, ==0:Could not delete due to any error */
+ _SYNC_t sobj /* Sync object tied to the logical drive to be deleted */
+)
+{
+ int ret;
+
+
+ ret = CloseHandle(sobj); /* Win32 */
+
+// ret = 1; /* uITRON (nothing to do) */
+
+// OSMutexDel(sobj, OS_DEL_ALWAYS, &err); /* uC/OS-II */
+// ret = (int)(err == OS_NO_ERR);
+
+// vSemaphoreDelete(sobj); /* FreeRTOS */
+// ret = 1;
+
+ return ret;
+}
+
+
+
+/*------------------------------------------------------------------------*/
+/* Request Grant to Access the Volume */
+/*------------------------------------------------------------------------*/
+/* This function is called on entering file functions to lock the volume.
+/ When a 0 is returned, the file function fails with FR_TIMEOUT.
+*/
+
+int ff_req_grant ( /* 1:Got a grant to access the volume, 0:Could not get a grant */
+ _SYNC_t sobj /* Sync object to wait */
+)
+{
+ int ret;
+
+ ret = (int)(WaitForSingleObject(sobj, _FS_TIMEOUT) == WAIT_OBJECT_0); /* Win32 */
+
+// ret = (int)(wai_sem(sobj) == E_OK); /* uITRON */
+
+// OSMutexPend(sobj, _FS_TIMEOUT, &err)); /* uC/OS-II */
+// ret = (int)(err == OS_NO_ERR);
+
+// ret = (int)(xSemaphoreTake(sobj, _FS_TIMEOUT) == pdTRUE); /* FreeRTOS */
+
+ return ret;
+}
+
+
+
+/*------------------------------------------------------------------------*/
+/* Release Grant to Access the Volume */
+/*------------------------------------------------------------------------*/
+/* This function is called on leaving file functions to unlock the volume.
+*/
+
+void ff_rel_grant (
+ _SYNC_t sobj /* Sync object to be signaled */
+)
+{
+ ReleaseMutex(sobj); /* Win32 */
+
+// sig_sem(sobj); /* uITRON */
+
+// OSMutexPost(sobj); /* uC/OS-II */
+
+// xSemaphoreGive(sobj); /* FreeRTOS */
+}
+
+#endif
+
+
+
+
+#if _USE_LFN == 3 /* LFN with a working buffer on the heap */
+/*------------------------------------------------------------------------*/
+/* Allocate a memory block */
+/*------------------------------------------------------------------------*/
+/* If a NULL is returned, the file function fails with FR_NOT_ENOUGH_CORE.
+*/
+
+void* ff_memalloc ( /* Returns pointer to the allocated memory block */
+ UINT msize /* Number of bytes to allocate */
+)
+{
+ return malloc(msize); /* Allocate a new memory block with POSIX API */
+}
+
+
+/*------------------------------------------------------------------------*/
+/* Free a memory block */
+/*------------------------------------------------------------------------*/
+
+void ff_memfree (
+ void* mblock /* Pointer to the memory block to free */
+)
+{
+ free(mblock); /* Discard the memory block with POSIX API */
+}
+
+#endif
diff --git a/emb/pastilda/fs/fatfs/option/unicode.c b/emb/pastilda/fs/fatfs/option/unicode.c
new file mode 100644
index 0000000..33def26
--- /dev/null
+++ b/emb/pastilda/fs/fatfs/option/unicode.c
@@ -0,0 +1,17 @@
+#include <fs/fatfs/ff.h>
+
+#if _USE_LFN != 0
+
+#if _CODE_PAGE == 932 /* Japanese Shift_JIS */
+#include "cc932.c"
+#elif _CODE_PAGE == 936 /* Simplified Chinese GBK */
+#include "cc936.c"
+#elif _CODE_PAGE == 949 /* Korean */
+#include "cc949.c"
+#elif _CODE_PAGE == 950 /* Traditional Chinese Big5 */
+#include "cc950.c"
+#else /* Single Byte Character-Set */
+#include "ccsbcs.c"
+#endif
+
+#endif
diff --git a/emb/pastilda/fs/file_system.cpp b/emb/pastilda/fs/file_system.cpp
new file mode 100644
index 0000000..ab7088d
--- /dev/null
+++ b/emb/pastilda/fs/file_system.cpp
@@ -0,0 +1,239 @@
+/*
+ * This file is part of the pastilda project.
+ * hosted at http://github.com/thirdpin/pastilda
+ *
+ * Copyright (C) 2016 Third Pin LLC
+ *
+ * Written by:
+ * Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ * Dmitrii Lisin <mrlisdim@ya.ru>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <fs/file_system.h>
+
+FileSystem *fs_pointer;
+
+FileSystem::FileSystem()
+{
+ fs_pointer = this;
+ _sst25.disable_write_protection();
+
+ uint16_t res = _sst25.read_id();
+ disk_set_callbacks(access_memory);
+
+ FatState state = get_fat_state();
+ if (state == FatState::FAT_ERROR) {
+ format_to_FAT12();
+ }
+ f_mount(&FATFS_Obj, "0", 1);
+}
+
+int FileSystem::access_memory(MemoryCommand cmd, uint32_t sector, uint32_t count, uint8_t *copy_to, const uint8_t *copy_from)
+{
+ switch(cmd)
+ {
+ case READ:
+ for(int i = 0; i < count; i++) {
+ fs_pointer->_sst25.read_sector(sector, &copy_to[FAKE_SECTOR_SIZE * i]);
+ sector++;
+ }
+ break;
+ case WRITE:
+ for(int i = 0; i < count; i++) {
+ fs_pointer->_sst25.write_sector(sector, copy_from);
+ sector++;
+ }
+ break;
+ }
+
+ return (count);
+}
+
+void FileSystem::erase_chip()
+{
+ _sst25.erase_full_chip();
+}
+
+int FileSystem::msd_read(uint32_t lba, uint8_t *copy_to)
+{
+ memset(copy_to, 0, FAKE_SECTOR_SIZE);
+ if (lba >= FAKE_SECTOR_COUNT) {
+ return (1);
+ }
+ else {
+ fs_pointer->_sst25.read_sector(lba, copy_to);
+ return (0);
+ }
+}
+
+int FileSystem::msd_write(uint32_t lba, const uint8_t *copy_from)
+{
+ if (lba >= FAKE_SECTOR_COUNT) {
+ return (1);
+ }
+ else {
+ fs_pointer->_sst25.write_sector(lba, copy_from);
+ return (0);
+ }
+}
+int FileSystem::msd_blocks(void)
+{
+ return (FAKE_SECTOR_COUNT);
+}
+
+
+FRESULT FileSystem::open_file_to_read(FIL *file, const char *name)
+{
+ return (f_open(file, name, FA_OPEN_EXISTING | FA_READ));
+}
+FRESULT FileSystem::open_file_to_write(FIL *file, const char *name)
+{
+ return (f_open(file, name, FA_CREATE_ALWAYS | FA_WRITE));
+}
+FRESULT FileSystem::close_file(FIL *file)
+{
+ return (f_close(file));
+}
+FRESULT FileSystem::read_next_file_chunk(FIL *file, void *buffer, uint32_t size)
+{
+ UINT nRead;
+ return (f_read(file, buffer, size, &nRead));
+}
+FRESULT FileSystem::write_next_file_chunk(FIL *file, void *buffer, uint32_t size)
+{
+ UINT nWritten;
+ return (f_write(file, buffer, size, &nWritten));
+}
+uint32_t FileSystem::get_file_tell(FIL *file)
+{
+ return (f_tell(file));
+}
+
+FRESULT FileSystem::read_file(FIL *file, const char *name, uint8_t *buffer)
+{
+ FRESULT result;
+ UINT nRead;
+
+ result = f_open(file, name, FA_OPEN_EXISTING | FA_READ);
+ if (result == FR_OK)
+ {
+ result = f_read(file, buffer, file->fsize, &nRead);
+ f_close(file);
+ }
+
+ return (result);
+}
+
+FRESULT FileSystem::write_file(FIL *file, const char *name, uint8_t *buffer, uint32_t size)
+{
+ FRESULT result;
+ UINT nWritten;
+
+ result = f_open(file, name, FA_CREATE_ALWAYS | FA_WRITE);
+ if (result == FR_OK)
+ {
+ f_write(file, buffer, size, &nWritten);
+ f_close(file);
+ }
+
+ return (result);
+}
+
+FatState FileSystem::get_fat_state()
+{
+ uint16_t signature;
+ uint8_t buf[BYTES_PER_SECTOR];
+
+ access_memory(READ, MBR_SECTOR, MBR_SECTORS_COUNT, buf, 0);
+ memcpy(&signature, &buf[SIGNATURE_OFFSET], sizeof(uint16_t));
+
+ if (signature == SIGNATURE) {
+ return (FatState::FAT_READY);
+ }
+
+ return (FatState::FAT_ERROR);
+}
+
+void FileSystem::format_to_FAT12()
+{
+ erase_chip();
+ _set_master_boot_record();
+ _set_FAT();
+ _set_root_directory();
+ scb_reset_system();
+}
+void FileSystem::_set_master_boot_record()
+{
+ Bpb_fat12_16 bpb;
+
+ memcpy(bpb.bpb_base.jump_boot, JUMP_BOOT_VALUE, JUMP_BOOT_SIZE);
+ memcpy(bpb.bpb_base.oem_name, OEM_NAME_VALUE, OEM_NAME_SIZE);
+ bpb.bpb_base.bytes_per_sector = BYTES_PER_SECTOR;
+ bpb.bpb_base.sectors_per_cluster = SECTORS_PER_CLUSTER;
+ bpb.bpb_base.reserved_sectors_count = RESERVED_SECTORS;
+ bpb.bpb_base.num_fats = FAT_COUNT;
+ bpb.bpb_base.root_entry_count = ROOT_ENTRY_COUNT;
+ bpb.bpb_base.total_sectors_fat16 = TOTAL_SECTORS_COUNT_FAT16;
+ bpb.bpb_base.media = REMOVABLE_MEDIA;
+ bpb.bpb_base.fat16_size = SECTORS_PER_FAT;
+ bpb.bpb_base.sector_per_track = SECTORS_PER_TRACK;
+ bpb.bpb_base. number_of_heads = NUMBER_OF_HEADS;
+ bpb.bpb_base.count_of_hidden_sectors = HIDDEN_SECTORS_COUNT;
+ bpb.bpb_base.total_sectors_fat32 = TOTAL_SECTORS_COUNT_FAT32;
+ bpb.drive_number = DRIVE_NUMBER;
+ bpb.reserved_1 = 0;
+ bpb.boot_signature = BOOT_SIGNATURE;
+ bpb.volume_serial_number = VOL_SERIAL_NUMBER;
+ memcpy(bpb.volume_label, VOLUME_LABLE_VALUE, VOLUME_LABLE_SIZE);
+ memcpy(bpb.filesystem_type, FS_TYPE_VALUE, FS_TYPE_SIZE);
+ bpb.volume_label[VOLUME_LABLE_SIZE];
+ bpb.filesystem_type[FS_TYPE_SIZE];
+
+ Partition part;
+ part.bootable = Bootable::PARTITION_ACTIVE;
+ part.first_head = 0;
+ part.first_sector = 0;
+ part.first_cylinder = 0;
+ part.type = PartitionType::FAT12;
+ part.last_head = 0;
+ part.last_sector = 0;
+ part.last_cylinder = 0;
+ part.first_lba = 0;
+ part.sector_count = TOTAL_SECTORS_COUNT_FAT16;
+
+ uint8_t boot_sector[BYTES_PER_SECTOR];
+ memset(boot_sector, 0, BYTES_PER_SECTOR);
+ memcpy(&boot_sector[BPB_OFFSET], &bpb, sizeof(Bpb_fat12_16));
+ memcpy(&boot_sector[PARTITION_OFFSET], &part, sizeof(Partition));
+ memcpy(&boot_sector[SIGNATURE_OFFSET], &SIGNATURE, sizeof(uint16_t));
+
+ access_memory(WRITE, MBR_SECTOR, MBR_SECTORS_COUNT, 0, boot_sector);
+}
+void FileSystem::_set_FAT()
+{
+ uint8_t fat_sector[BYTES_PER_FAT];
+ memset(fat_sector, 0, BYTES_PER_FAT);
+ memcpy(fat_sector, FAT_HEADER, FAT_HEADER_SIZE);
+
+ access_memory(WRITE, FAT1_SECTOR, FAT_SECTORS_COUNT, 0, fat_sector);
+ access_memory(WRITE, FAT2_SECTOR, FAT_SECTORS_COUNT, 0, fat_sector);
+}
+void FileSystem::_set_root_directory()
+{
+ uint8_t root_sector[BYTES_PER_ROOT];
+ memset(root_sector, 0, BYTES_PER_ROOT);
+ access_memory(WRITE, ROOT_SECTOR, ROOT_SECTORS_COUNT, 0, root_sector);
+}
diff --git a/emb/pastilda/fs/file_system.h b/emb/pastilda/fs/file_system.h
new file mode 100644
index 0000000..18125b7
--- /dev/null
+++ b/emb/pastilda/fs/file_system.h
@@ -0,0 +1,64 @@
+/*
+ * This file is part of the pastilda project.
+ * hosted at http://github.com/thirdpin/pastilda
+ *
+ * Copyright (C) 2016 Third Pin LLC
+ *
+ * Written by:
+ * Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ * Dmitrii Lisin <mrlisdim@ya.ru>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef FILE_SYSTEM_H
+#define FILE_SYSTEM_H
+
+#include <fs/fatfs/diskio.h>
+#include <fs/fatfs/ff.h>
+#include <fs/file_system_defines.h>
+#include <libopencm3/cm3/scb.h>
+
+class FileSystem
+{
+public:
+ FATFS FATFS_Obj;
+ FileSystem();
+
+ static int access_memory(MemoryCommand cmd, uint32_t sector, uint32_t count, uint8_t *copy_to, const uint8_t *copy_from);
+ void erase_chip();
+ void format_to_FAT12();
+
+ static int msd_read(uint32_t lba, uint8_t *copy_to);
+ static int msd_write(uint32_t lba, const uint8_t *copy_from);
+ static int msd_blocks(void);
+
+ static FRESULT open_file_to_read(FIL *file, const char *name);
+ static FRESULT open_file_to_write(FIL *file, const char *name);
+ static FRESULT close_file(FIL *file);
+ static FRESULT read_next_file_chunk(FIL *file, void *buffer, uint32_t size);
+ static FRESULT write_next_file_chunk(FIL *file, void *buffer, uint32_t size);
+ static uint32_t get_file_tell(FIL *file);
+ static FRESULT read_file(FIL *file, const char *name, uint8_t *buffer);
+ static FRESULT write_file(FIL *file, const char *name, uint8_t *buffer, uint32_t size);
+
+private:
+ SST25 _sst25;
+ FatState get_fat_state();
+
+ void _set_master_boot_record();
+ void _set_FAT();
+ void _set_root_directory();
+};
+#endif
diff --git a/emb/pastilda/fs/file_system_defines.h b/emb/pastilda/fs/file_system_defines.h
new file mode 100644
index 0000000..b502864
--- /dev/null
+++ b/emb/pastilda/fs/file_system_defines.h
@@ -0,0 +1,161 @@
+/*
+ * This file is part of the pastilda project.
+ * hosted at http://github.com/thirdpin/pastilda
+ *
+ * Copyright (C) 2016 Third Pin LLC
+ *
+ * Written by:
+ * Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ * Dmitrii Lisin <mrlisdim@ya.ru>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef FILE_SYSTEM_DEFINES_H
+#define FILE_SYSTEM_DEFINES_H
+
+#include <fs/drv/SST25.h>
+#include <string.h>
+#include "spi_ext.h"
+
+typedef enum
+{
+ READ,
+ WRITE
+}MemoryCommand;
+
+struct UsbMemoryControlParams {
+ const int block_count;
+ int (*read_block_func)(uint32_t lba, uint8_t *copy_to);
+ int (*write_block_func)(uint32_t lba, const uint8_t *copy_from);
+};
+
+struct FatMemoryControlParams {
+ int (*access_memory_func)(MemoryCommand cmd, uint32_t sector, uint32_t count, void *buf);
+};
+
+constexpr uint16_t FAKE_SECTOR_COUNT = 2048;//(MEMORY_SIZE / FAKE_SECTOR_SIZE);
+
+constexpr uint8_t JUMP_BOOT_SIZE = 3;
+constexpr uint8_t JUMP_BOOT_VALUE[JUMP_BOOT_SIZE] = {0xEB, 0xFF, 0x90};
+constexpr uint8_t OEM_NAME_SIZE = 8;
+constexpr uint8_t OEM_NAME_VALUE[OEM_NAME_SIZE] = {'M','S','W','I','N','4','.','1'};
+constexpr uint16_t BYTES_PER_SECTOR = 512;
+constexpr uint8_t SECTORS_PER_CLUSTER = 8;
+constexpr uint16_t RESERVED_SECTORS = 1;
+constexpr uint8_t FAT_COUNT = 2;
+constexpr uint16_t ROOT_ENTRY_COUNT = 512;
+constexpr uint16_t TOTAL_SECTORS_COUNT_FAT16 = 2048;//16384;
+constexpr uint8_t REMOVABLE_MEDIA = 0xF8;
+constexpr uint16_t SECTORS_PER_FAT = 1;
+constexpr uint16_t SECTORS_PER_TRACK = 0;
+constexpr uint16_t NUMBER_OF_HEADS = 0;
+constexpr uint32_t HIDDEN_SECTORS_COUNT = 0;
+constexpr uint32_t TOTAL_SECTORS_COUNT_FAT32 = 0;
+constexpr uint8_t DRIVE_NUMBER = 0x80;
+constexpr uint8_t BOOT_SIGNATURE = 0x29;
+constexpr uint32_t VOL_SERIAL_NUMBER = 0xC4B1CDCF;
+constexpr uint8_t VOLUME_LABLE_SIZE = 11;
+constexpr uint8_t VOLUME_LABLE_VALUE[VOLUME_LABLE_SIZE] = {'N','O',' ','N','A','M','E',' ',' ',' ',' '};
+constexpr uint8_t FS_TYPE_SIZE = 8;
+constexpr uint8_t FS_TYPE_VALUE[FS_TYPE_SIZE] = {'F','A','T',' ','1','2',' ',' '};
+constexpr uint16_t SIGNATURE = 0xAA55;
+
+constexpr uint8_t BPB_OFFSET = 0;
+constexpr uint16_t PARTITION_OFFSET = 446;
+constexpr uint16_t SIGNATURE_OFFSET = 510;
+
+constexpr uint8_t MBR_SECTOR = 0;
+constexpr uint8_t MBR_SECTORS_COUNT = 1;
+
+constexpr uint8_t FAT1_SECTOR = 1;
+constexpr uint8_t FAT_SECTORS_COUNT = 1;
+constexpr uint16_t BYTES_PER_FAT = (FAT_SECTORS_COUNT * BYTES_PER_SECTOR);
+constexpr uint8_t FAT2_SECTOR = (FAT1_SECTOR + FAT_SECTORS_COUNT);
+constexpr uint8_t FAT_HEADER_SIZE = 4;
+constexpr uint8_t FAT_HEADER[FAT_HEADER_SIZE] = {0xF8, 0xFF, 0xFF, 0xFF};
+
+constexpr uint8_t ROOT_SECTOR = (FAT2_SECTOR + FAT_SECTORS_COUNT);
+constexpr uint8_t ROOT_SECTORS_COUNT = 32;
+constexpr uint16_t BYTES_PER_ROOT = (ROOT_SECTORS_COUNT * BYTES_PER_SECTOR);
+
+constexpr uint8_t NUMBER_OF_CHARS = 30;
+constexpr uint8_t NUMBER_OF_FILES = 50;
+
+#pragma pack (push, 1)
+typedef struct {
+ uint8_t jump_boot[JUMP_BOOT_SIZE];
+ uint8_t oem_name[OEM_NAME_SIZE];
+ uint16_t bytes_per_sector;
+ uint8_t sectors_per_cluster;
+ uint16_t reserved_sectors_count;
+ uint8_t num_fats;
+ uint16_t root_entry_count;
+ uint16_t total_sectors_fat16;
+ uint8_t media;
+ uint16_t fat16_size;
+ uint16_t sector_per_track;
+ uint16_t number_of_heads;
+ uint32_t count_of_hidden_sectors;
+ uint32_t total_sectors_fat32;
+}Bpb_base;
+
+typedef struct {
+ Bpb_base bpb_base;
+ uint8_t drive_number;
+ uint8_t reserved_1;
+ uint8_t boot_signature;
+ uint32_t volume_serial_number;
+ uint8_t volume_label[VOLUME_LABLE_SIZE];
+ uint8_t filesystem_type[FS_TYPE_SIZE];
+}Bpb_fat12_16;
+
+typedef struct {
+ uint8_t bootable;
+ uint8_t first_head;
+ uint8_t first_sector;
+ uint8_t first_cylinder;
+ uint8_t type;
+ uint8_t last_head;
+ uint8_t last_sector;
+ uint8_t last_cylinder;
+ uint32_t first_lba;
+ uint32_t sector_count;
+}Partition;
+#pragma pack (pop)
+
+typedef enum {
+ FAT12 = 0x01,
+ FAT16_UNDER_32MB = 0x04,
+ FAT16 = 0x06,
+ FAT32 = 0x0B,
+ FAT32_LBA = 0x0C
+}PartitionType;
+
+typedef enum {
+ PARTITION_ACTIVE = 0x80,
+ PARTITION_INACTIVE = 0x00
+}Bootable;
+
+typedef enum {
+ FAT_READY,
+ FAT_ERROR
+}FatState;
+
+typedef enum : uint8_t {
+ OK = 0,
+ ERROR = 1
+}Result;
+
+#endif
diff --git a/emb/pastilda/keepass/keepass_crypto.cpp b/emb/pastilda/keepass/keepass_crypto.cpp
new file mode 100644
index 0000000..fa3ae9f
--- /dev/null
+++ b/emb/pastilda/keepass/keepass_crypto.cpp
@@ -0,0 +1,87 @@
+/*
+ * This file is part of the pastilda project.
+ * hosted at http://github.com/thirdpin/pastilda
+ *
+ * Copyright (C) 2016 Third Pin LLC
+ *
+ * Written by:
+ * Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ * Dmitrii Lisin <mrlisdim@ya.ru>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "keepass_crypto.h"
+
+using namespace KeepAss;
+
+void KeePassCrypto::evalSHA256(const uint8_t *data, uint32_t len, uint8_t *hash)
+{
+ cf_sha256_context ctx;
+ cf_sha256_init(&ctx);
+ cf_sha256_update(&ctx, data, len);
+ cf_sha256_digest_final(&ctx, hash);
+}
+
+void KeePassCrypto::encrypt_AES_EBC(uint8_t *key, uint8_t *data, uint32_t data_len, uint32_t cycles)
+{
+ crypto_set_key(CRYPTO_KEY_256BIT, key);
+ crypto_set_algorithm(ENCRYPT_AES_ECB);
+ crypto_set_datatype(CRYPTO_DATA_8BIT);
+ crypto_start();
+
+ for (int i = 0; i < cycles; i++) {
+ crypto_process_block((uint32_t*)data, (uint32_t*)data, data_len / sizeof(uint32_t));
+ }
+
+ crypto_stop();
+}
+
+void KeePassCrypto::decrypt_AES_CBC(uint8_t *key, uint8_t *iv, uint8_t *data, uint32_t data_len)
+{
+ crypto_set_key(CRYPTO_KEY_256BIT, key);
+ crypto_set_iv(iv);
+ crypto_set_datatype(CRYPTO_DATA_8BIT);
+ crypto_set_algorithm(crypto_mode::DECRYPT_AES_CBC);
+ crypto_start();
+ crypto_process_block((uint32_t*)data, (uint32_t*)data, data_len / sizeof(uint32_t));
+ crypto_stop();
+}
+
+static Salsa20 salsa;
+static uint8_t key_stream[Salsa20::BLOCK_SIZE];
+static uint8_t stream_pointer;
+
+void KeePassCrypto::init_Salsa20(uint8_t *key, const uint8_t *iv)
+{
+ salsa.setKey(key);
+ salsa.setIv(iv);
+ stream_pointer = 0;
+ memset(key_stream, 0, Salsa20::BLOCK_SIZE);
+ salsa.generateKeyStream(key_stream);
+}
+
+void KeePassCrypto::eval_Salsa20(uint8_t *input, uint32_t length)
+{
+ for (int i = 0; i < length; i++) {
+ input[i] = input[i] ^ key_stream[stream_pointer];
+ stream_pointer++;
+
+ if (stream_pointer >= Salsa20::BLOCK_SIZE) {
+ memset(key_stream, 0, Salsa20::BLOCK_SIZE);
+ salsa.generateKeyStream(key_stream);
+ stream_pointer = 0;
+ }
+ }
+}
diff --git a/emb/pastilda/keepass/keepass_crypto.h b/emb/pastilda/keepass/keepass_crypto.h
new file mode 100644
index 0000000..9428dfe
--- /dev/null
+++ b/emb/pastilda/keepass/keepass_crypto.h
@@ -0,0 +1,50 @@
+/*
+ * This file is part of the pastilda project.
+ * hosted at http://github.com/thirdpin/pastilda
+ *
+ * Copyright (C) 2016 Third Pin LLC
+ *
+ * Written by:
+ * Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ * Dmitrii Lisin <mrlisdim@ya.ru>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CRYPTO_H
+#define CRYPTO_H
+
+#include <lib/crypto/base64.h>
+#include <lib/crypto/salsa20.h>
+#include <stdint.h>
+#include <string.h>
+#include <libopencm3/stm32/crypto.h>
+extern "C" {
+#include <lib/crypto/sha2.h>
+}
+
+namespace KeepAss
+{
+ class KeePassCrypto
+ {
+ public:
+ KeePassCrypto() {};
+ static void evalSHA256(const uint8_t *data, uint32_t len, uint8_t *hash);
+ static void encrypt_AES_EBC(uint8_t *key, uint8_t *data, uint32_t data_len, uint32_t cycles);
+ static void decrypt_AES_CBC(uint8_t *key, uint8_t *iv, uint8_t *data, uint32_t data_len);
+ static void init_Salsa20(uint8_t *key, const uint8_t *iv);
+ static void eval_Salsa20(uint8_t *input, uint32_t length);
+ };
+}
+#endif
diff --git a/emb/pastilda/keepass/keepass_reader.cpp b/emb/pastilda/keepass/keepass_reader.cpp
new file mode 100644
index 0000000..87de844
--- /dev/null
+++ b/emb/pastilda/keepass/keepass_reader.cpp
@@ -0,0 +1,270 @@
+/*
+ * This file is part of the pastilda project.
+ * hosted at http://github.com/thirdpin/pastilda
+ *
+ * Copyright (C) 2016 Third Pin LLC
+ *
+ * Written by:
+ * Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ * Dmitrii Lisin <mrlisdim@ya.ru>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <keepass_reader.h>
+
+using namespace KeepAss;
+
+constexpr uint8_t KeePassReader::IV_SALSA[8];
+
+KeePassReader::KeePassReader()
+{
+ _tree = nullptr;
+ _signature1 = 0;
+ _signature2 = 0;
+ _signature3 = 0;
+ _keyf_len = 0;
+ _pass_len = 0;
+ _file_len = 0;
+ _credentials = KeePassCredentials::NOT_SELECTED;
+}
+
+DecryptionResult KeePassReader::_checkKeePassVersion()
+{
+ FileSystem::read_next_file_chunk(&_file, &_signature1, sizeof(uint32_t));
+ FileSystem::read_next_file_chunk(&_file, &_signature2, sizeof(uint32_t));
+
+ bool sig1correct = (_signature1 == SIGNATURE_1);
+ bool sig2correct = ((_signature2 == SIGNATURE_2_2X_PRE_RELEASE)||
+ (_signature2 == SIGNATURE_2_2X_POST_RELEASE));
+
+ if(sig1correct && sig2correct) {
+ return (DecryptionResult::SUCCESS);
+ }
+
+ return (DecryptionResult::SIGNATURE_ERROR);
+}
+
+void KeePassReader::_readHeader()
+{
+ uint8_t nfield;
+ memset(_header, 0, sizeof(_header));
+
+ //first 4 bytes in header = database version
+ FileSystem::read_next_file_chunk(&_file, &_signature3, sizeof(uint32_t));
+
+ //data in header organized as follows:
+ //1 byte = number of header field
+ //2 bytes = size of header filed
+ //[size of header filed] bytes
+ for(int i = 0; i < HEADER_FIELD_COUNT; i++) {
+ FileSystem::read_next_file_chunk(&_file, &nfield, sizeof(uint8_t));
+
+ if (nfield < HEADER_FIELD_COUNT) {
+ FileSystem::read_next_file_chunk(&_file, &_header[nfield].size, sizeof(uint16_t));
+ FileSystem::read_next_file_chunk(&_file, _header[nfield].data, _header[nfield].size);
+ }
+ if(nfield == END_OF_HEADER) {
+ break;
+ }
+ }
+}
+
+void KeePassReader::_makeMasterKey(uint8_t *key, uint32_t key_len)
+{
+ uint8_t hash1[HASH_LENGTH];
+ uint8_t hash2[HASH_LENGTH];
+
+ KeePassCrypto::evalSHA256(key, key_len, hash1);
+ KeePassCrypto::evalSHA256(hash1, HASH_LENGTH, hash2);
+
+ _makeKeyRoutine(hash2);
+}
+
+void KeePassReader::_makeMasterKey(uint8_t *pass, uint8_t *keyfile, uint32_t pass_len, uint32_t keylile_len)
+{
+ uint8_t composite[COMPOSITE_KEY_LENGTH];
+ uint8_t composite_hash[HASH_LENGTH];
+
+ //getting hash of a password and key file
+ KeePassCrypto::evalSHA256(pass, pass_len, &composite[0]);
+ KeePassCrypto::evalSHA256(keyfile, keylile_len, &composite[HASH_LENGTH]);
+
+ //getting hash of a composite key
+ KeePassCrypto::evalSHA256(composite, COMPOSITE_KEY_LENGTH, composite_hash);
+
+ //the main make key routine is the same as for keepass v.1
+ _makeKeyRoutine(composite_hash);
+}
+
+void KeePassReader::_makeKeyRoutine(uint8_t *key_hash)
+{
+ uint8_t final_key[MASTER_KEY_LENGTH_2X];
+ memcpy(&final_key[0], _header[MASTER_SEED].data, _header[MASTER_SEED].size);
+
+ uint16_t rounds = (*(uint16_t*)_header[TRANSFORM_ROUNDS].data);
+
+ KeePassCrypto::encrypt_AES_EBC(_header[TRANSFORM_SEED].data, key_hash, HASH_LENGTH, rounds);
+
+ KeePassCrypto::evalSHA256(key_hash, HASH_LENGTH, &final_key[_header[MASTER_SEED].size]);
+ KeePassCrypto::evalSHA256(final_key, MASTER_KEY_LENGTH_2X, _master_key);
+}
+
+DecryptionResult KeePassReader::_decrypt()
+{
+ uint8_t hash[HASH_LENGTH];
+ memset(_decrypted_data, 0, MAX_DATABASE_SIZE_IN_BYTES);
+
+ _file_len = _file.fsize - FileSystem::get_file_tell(&_file);
+ FileSystem::read_next_file_chunk(&_file, _decrypted_data, _file_len);
+ if (FileSystem::close_file(&_file) != FR_OK) {
+ return (DB_FILE_ERROR);
+ }
+
+ KeePassCrypto::decrypt_AES_CBC(_master_key, _header[ENCRYPTION_IV].data, _decrypted_data, _file_len);
+
+ if (memcmp(_header[STREAM_START_BYTES].data, _decrypted_data, _header[STREAM_START_BYTES].size)) {
+ return (MASTER_KEY_ERROR);
+ }
+
+ _file_len -= _header[STREAM_START_BYTES].size;
+ return (_process_blocks());
+}
+
+DecryptionResult KeePassReader::_process_blocks()
+{
+ uint8_t hash[HASH_LENGTH];
+ uint32_t data_size = 0;
+ uint32_t offset = _header[STREAM_START_BYTES].size;
+ BlockDataHeader block_data;
+
+ while (_file_len > sizeof(BlockDataHeader))
+ {
+ memcpy(&block_data, &_decrypted_data[offset], sizeof(BlockDataHeader));
+
+ if (block_data.blockDataSize == 0) {
+ break;
+ }
+
+ KeePassCrypto::evalSHA256(&_decrypted_data[offset + sizeof(BlockDataHeader)], block_data.blockDataSize, hash);
+
+ if(!memcmp(block_data.blockDataHash, hash, HASH_LENGTH)) {
+ memcpy(&_decrypted_data[data_size], &_decrypted_data[offset + sizeof(BlockDataHeader)], block_data.blockDataSize);
+ offset += sizeof(BlockDataHeader) + block_data.blockDataSize;
+ data_size += block_data.blockDataSize;
+ _file_len = (_file_len - sizeof(BlockDataHeader) - block_data.blockDataSize);
+ }
+
+ else {
+ return (DATA_HASH_ERROR);
+ }
+ }
+
+ _decrypted_data[data_size++] = EOF;
+ memset(&_decrypted_data[data_size], 0, (MAX_DATABASE_SIZE_IN_BYTES - data_size));
+ _decrypt_passwords();
+ return (SUCCESS);
+}
+
+void KeePassReader::_decrypt_passwords()
+{
+ uint32_t decoded_len = 0;
+ uint8_t hash[HASH_LENGTH];
+ uint8_t decrypted_pass[MAX_PASSWORD_SIZE_IN_BYTES] = {0};
+
+ KeePassCrypto::evalSHA256(_header[PROTECTED_STREAM_KEY].data, _header[PROTECTED_STREAM_KEY].size, hash);
+ KeePassCrypto::init_Salsa20(hash, IV_SALSA);
+
+ if (_tree == nullptr) {
+ _tree = mxmlLoadString(NULL,
+ (const char*)_decrypted_data,
+ MXML_OPAQUE_CALLBACK);
+
+ mxml_node_t *last_node = _tree;
+ mxml_node_t *curr_node;
+
+ while(true)
+ {
+ curr_node = mxmlFindElement(last_node, _tree, "Value", "Protected", "True", MXML_DESCEND);
+
+ if (curr_node == NULL) {
+ break;
+ }
+
+ memset(decrypted_pass, 0, MAX_PASSWORD_SIZE_IN_BYTES);
+ uint32_t len = strlen(curr_node->child->value.opaque);
+
+ Base64::Decode(curr_node->child->value.opaque, len, (char*)decrypted_pass, len, &decoded_len);
+ KeePassCrypto::eval_Salsa20(decrypted_pass, decoded_len);
+
+ // curr_node->value.element.attrs[0].value = (char*)"False";
+ std::strcpy(curr_node->child->value.opaque, (char*)decrypted_pass);
+
+ last_node = curr_node;
+ }
+ }
+}
+
+mxml_node_t* KeePassReader::get_xml()
+{
+ return (_tree);
+}
+
+void KeePassReader::set_password(const char* pass, uint32_t len)
+{
+ if (len > 0) {
+ memcpy(_pass, pass, len);
+ _pass_len = len;
+ }
+ else {
+ _pass_len = 0;
+ }
+}
+
+DecryptionResult KeePassReader::decrypt_database(const char* db_name)
+{
+ //TODO: move to another place
+ _credentials = KeePassCredentials::PASSWORD;
+ ////////////////////////////////////////////
+
+ DecryptionResult result;
+
+ if (FileSystem::open_file_to_read(&_file, db_name) != FR_OK) {
+ return (DB_FILE_ERROR);
+ }
+
+ result = _checkKeePassVersion();
+ if (result != SUCCESS) {
+ FileSystem::close_file(&_file);
+ return (result);
+ }
+
+ if (_credentials == KeePassCredentials::NOT_SELECTED) {
+ FileSystem::close_file(&_file);
+ return (CREDENTIALS_ERROR);
+ }
+
+ _readHeader();
+
+ if (_credentials == KeePassCredentials::PASSWORD)
+ _makeMasterKey(_pass, _pass_len);
+
+ if (_credentials == KeePassCredentials::KEY_FILE)
+ _makeMasterKey(_keyf, _keyf_len);
+
+ if (_credentials == KeePassCredentials::PASSWORD_AND_KEY_FILE)
+ _makeMasterKey(_pass, _keyf, _pass_len, _keyf_len );
+
+ return (_decrypt());
+}
diff --git a/emb/pastilda/keepass/keepass_reader.h b/emb/pastilda/keepass/keepass_reader.h
new file mode 100644
index 0000000..9f1d1a7
--- /dev/null
+++ b/emb/pastilda/keepass/keepass_reader.h
@@ -0,0 +1,75 @@
+/*
+ * This file is part of the pastilda project.
+ * hosted at http://github.com/thirdpin/pastilda
+ *
+ * Copyright (C) 2016 Third Pin LLC
+ *
+ * Written by:
+ * Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ * Dmitrii Lisin <mrlisdim@ya.ru>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef KEEPASS_READER_H
+#define KEEPASS_READER_H
+
+#include <fs/file_system.h>
+#include <stdint.h>
+#include <string.h>
+#include "keepass_crypto.h"
+#include "keepass_reader_defines.h"
+extern "C" {
+#include "mxml.h"
+}
+
+namespace KeepAss
+{
+ class KeePassReader
+ {
+ public:
+ KeePassReader();
+ void set_password(const char* pass, uint32_t len);
+ DecryptionResult decrypt_database(const char *db_name);
+ mxml_node_t *get_xml();
+
+ private:
+ static constexpr uint8_t IV_SALSA[8] = {0xE8, 0x30, 0x09, 0x4B, 0x97, 0x20, 0x5D, 0x2A};
+ FIL _file;
+ uint32_t _signature1;
+ uint32_t _signature2;
+ uint32_t _signature3;
+ HeaderField _header[HEADER_FIELD_COUNT];
+ uint8_t _pass[MAX_PASSWORD_SIZE_IN_BYTES];
+ uint32_t _pass_len;
+ uint8_t _keyf[MAX_KEYFILE_SIZE_IN_BYTES];
+ uint32_t _keyf_len;
+ uint8_t _master_key[HASH_LENGTH];
+ KeePassCredentials _credentials;
+ uint8_t _decrypted_data[MAX_DATABASE_SIZE_IN_BYTES];
+ uint32_t _file_len;
+ mxml_node_t *_tree;
+
+ DecryptionResult _checkKeePassVersion();
+ void _readHeader();
+ void _makeMasterKey(uint8_t *key, uint32_t key_len);
+ void _makeMasterKey(uint8_t *pass, uint8_t *keyfile, uint32_t pass_len, uint32_t keylile_len);
+ void _makeKeyRoutine(uint8_t *key_hash);
+ DecryptionResult _decrypt();
+ DecryptionResult _process_blocks();
+ void _decrypt_passwords();
+
+ };
+}
+#endif
diff --git a/emb/pastilda/keepass/keepass_reader_defines.h b/emb/pastilda/keepass/keepass_reader_defines.h
new file mode 100644
index 0000000..df9ed53
--- /dev/null
+++ b/emb/pastilda/keepass/keepass_reader_defines.h
@@ -0,0 +1,92 @@
+/*
+ * This file is part of the pastilda project.
+ * hosted at http://github.com/thirdpin/pastilda
+ *
+ * Copyright (C) 2016 Third Pin LLC
+ *
+ * Written by:
+ * Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ * Dmitrii Lisin <mrlisdim@ya.ru>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef KEEPASS_READER_DEFINES_H
+#define KEEPASS_READER_DEFINES_H
+
+namespace KeepAss
+{
+ constexpr uint32_t SIGNATURE_1 = 0x9AA2D903;
+ constexpr uint32_t SIGNATURE_2_2X_PRE_RELEASE = 0xB54BFB66;
+ constexpr uint32_t SIGNATURE_2_2X_POST_RELEASE = 0xB54BFB67;
+ constexpr uint32_t HEADER_OFFSET_IN_BYTES = 8;
+ constexpr uint32_t MAX_PASSWORD_SIZE_IN_BYTES = 32;
+ constexpr uint32_t MAX_KEYFILE_SIZE_IN_BYTES = 32;
+ constexpr uint32_t HASH_LENGTH = 32;
+ constexpr uint32_t COMPOSITE_KEY_LENGTH = 64;
+ constexpr uint32_t MASTER_KEY_LENGTH_2X = 64;
+ constexpr uint32_t MAX_DATABASE_SIZE_IN_BYTES = 30000;
+ constexpr uint32_t MAX_HEADER_FIELD_SIZE = 32;
+
+ #pragma pack(push, 1)
+ typedef struct
+ {
+ uint16_t size;
+ uint8_t data[MAX_HEADER_FIELD_SIZE];
+ } HeaderField;
+
+ typedef struct
+ {
+ uint32_t blockID;
+ uint8_t blockDataHash[HASH_LENGTH];
+ uint32_t blockDataSize;
+ } BlockDataHeader;
+ #pragma pack(pop)
+
+
+ typedef enum : uint8_t
+ {
+ END_OF_HEADER = 0,
+ COMMENT = 1,
+ CIPHER_ID = 2,
+ COMPRESSION_FLAGS = 3,
+ MASTER_SEED = 4,
+ TRANSFORM_SEED = 5,
+ TRANSFORM_ROUNDS = 6,
+ ENCRYPTION_IV = 7,
+ PROTECTED_STREAM_KEY = 8,
+ STREAM_START_BYTES = 9,
+ INNER_RANDOM_STREAM_ID = 10,
+ HEADER_FIELD_COUNT = 11
+ } HeaderFieldName;
+
+ typedef enum
+ {
+ NOT_SELECTED,
+ PASSWORD,
+ KEY_FILE,
+ PASSWORD_AND_KEY_FILE
+ } KeePassCredentials;
+
+ typedef enum
+ {
+ SUCCESS,
+ SIGNATURE_ERROR,
+ MASTER_KEY_ERROR,
+ CREDENTIALS_ERROR,
+ DB_FILE_ERROR,
+ DATA_HASH_ERROR,
+ } DecryptionResult;
+}
+#endif
diff --git a/emb/pastilda/keyboard.h b/emb/pastilda/keyboard.h
deleted file mode 100644
index 7a59e41..0000000
--- a/emb/pastilda/keyboard.h
+++ /dev/null
@@ -1,237 +0,0 @@
-#ifndef KEYBOARD_H
-#define KEYBOARD_H
-
-#define KEY_NONE 0x00
-#define KEY_ERRORROLLOVER 0x01
-#define KEY_POSTFAIL 0x02
-#define KEY_ERRORUNDEFINED 0x03
-#define KEY_A 0x04
-#define KEY_B 0x05
-#define KEY_C 0x06
-#define KEY_D 0x07
-#define KEY_E 0x08
-#define KEY_F 0x09
-#define KEY_G 0x0A
-#define KEY_H 0x0B
-#define KEY_I 0x0C
-#define KEY_J 0x0D
-#define KEY_K 0x0E
-#define KEY_L 0x0F
-#define KEY_M 0x10
-#define KEY_N 0x11
-#define KEY_O 0x12
-#define KEY_P 0x13
-#define KEY_Q 0x14
-#define KEY_R 0x15
-#define KEY_S 0x16
-#define KEY_T 0x17
-#define KEY_U 0x18
-#define KEY_V 0x19
-#define KEY_W 0x1A
-#define KEY_X 0x1B
-#define KEY_Y 0x1C
-#define KEY_Z 0x1D
-#define KEY_1_EXCLAMATION_MARK 0x1E
-#define KEY_2_AT 0x1F
-#define KEY_3_NUMBER_SIGN 0x20
-#define KEY_4_DOLLAR 0x21
-#define KEY_5_PERCENT 0x22
-#define KEY_6_CARET 0x23
-#define KEY_7_AMPERSAND 0x24
-#define KEY_8_ASTERISK 0x25
-#define KEY_9_OPARENTHESIS 0x26
-#define KEY_0_CPARENTHESIS 0x27
-#define KEY_ENTER 0x28
-#define KEY_ESCAPE 0x29
-#define KEY_BACKSPACE 0x2A
-#define KEY_TAB 0x2B
-#define KEY_SPACEBAR 0x2C
-#define KEY_MINUS_UNDERSCORE 0x2D
-#define KEY_EQUAL_PLUS 0x2E
-#define KEY_OBRACKET_AND_OBRACE 0x2F
-#define KEY_CBRACKET_AND_CBRACE 0x30
-#define KEY_BACKSLASH_VERTICAL_BAR 0x31
-#define KEY_NONUS_NUMBER_SIGN_TILDE 0x32
-#define KEY_SEMICOLON_COLON 0x33
-#define KEY_SINGLE_AND_DOUBLE_QUOTE 0x34
-#define KEY_GRAVE_ACCENT_AND_TILDE 0x35
-#define KEY_COMMA_AND_LESS 0x36
-#define KEY_DOT_GREATER 0x37
-#define KEY_SLASH_QUESTION 0x38
-#define KEY_CAPS_LOCK 0x39
-#define KEY_F1 0x3A
-#define KEY_F2 0x3B
-#define KEY_F3 0x3C
-#define KEY_F4 0x3D
-#define KEY_F5 0x3E
-#define KEY_F6 0x3F
-#define KEY_F7 0x40
-#define KEY_F8 0x41
-#define KEY_F9 0x42
-#define KEY_F10 0x43
-#define KEY_F11 0x44
-#define KEY_F12 0x45
-#define KEY_PRINTSCREEN 0x46
-#define KEY_SCROLL_LOCK 0x47
-#define KEY_PAUSE 0x48
-#define KEY_INSERT 0x49
-#define KEY_HOME 0x4A
-#define KEY_PAGEUP 0x4B
-#define KEY_DELETE 0x4C
-#define KEY_END1 0x4D
-#define KEY_PAGEDOWN 0x4E
-#define KEY_RIGHTARROW 0x4F
-#define KEY_LEFTARROW 0x50
-#define KEY_DOWNARROW 0x51
-#define KEY_UPARROW 0x52
-#define KEY_KEYPAD_NUM_LOCK_AND_CLEAR 0x53
-#define KEY_KEYPAD_SLASH 0x54
-#define KEY_KEYPAD_ASTERIKS 0x55
-#define KEY_KEYPAD_MINUS 0x56
-#define KEY_KEYPAD_PLUS 0x57
-#define KEY_KEYPAD_ENTER 0x58
-#define KEY_KEYPAD_1_END 0x59
-#define KEY_KEYPAD_2_DOWN_ARROW 0x5A
-#define KEY_KEYPAD_3_PAGEDN 0x5B
-#define KEY_KEYPAD_4_LEFT_ARROW 0x5C
-#define KEY_KEYPAD_5 0x5D
-#define KEY_KEYPAD_6_RIGHT_ARROW 0x5E
-#define KEY_KEYPAD_7_HOME 0x5F
-#define KEY_KEYPAD_8_UP_ARROW 0x60
-#define KEY_KEYPAD_9_PAGEUP 0x61
-#define KEY_KEYPAD_0_INSERT 0x62
-#define KEY_KEYPAD_DECIMAL_SEPARATOR_DELETE 0x63
-#define KEY_NONUS_BACK_SLASH_VERTICAL_BAR 0x64
-#define KEY_APPLICATION 0x65
-#define KEY_POWER 0x66
-#define KEY_KEYPAD_EQUAL 0x67
-#define KEY_F13 0x68
-#define KEY_F14 0x69
-#define KEY_F15 0x6A
-#define KEY_F16 0x6B
-#define KEY_F17 0x6C
-#define KEY_F18 0x6D
-#define KEY_F19 0x6E
-#define KEY_F20 0x6F
-#define KEY_F21 0x70
-#define KEY_F22 0x71
-#define KEY_F23 0x72
-#define KEY_F24 0x73
-#define KEY_EXECUTE 0x74
-#define KEY_HELP 0x75
-#define KEY_MENU 0x76
-#define KEY_SELECT 0x77
-#define KEY_STOP 0x78
-#define KEY_AGAIN 0x79
-#define KEY_UNDO 0x7A
-#define KEY_CUT 0x7B
-#define KEY_COPY 0x7C
-#define KEY_PASTE 0x7D
-#define KEY_FIND 0x7E
-#define KEY_MUTE 0x7F
-#define KEY_VOLUME_UP 0x80
-#define KEY_VOLUME_DOWN 0x81
-#define KEY_LOCKING_CAPS_LOCK 0x82
-#define KEY_LOCKING_NUM_LOCK 0x83
-#define KEY_LOCKING_SCROLL_LOCK 0x84
-#define KEY_KEYPAD_COMMA 0x85
-#define KEY_KEYPAD_EQUAL_SIGN 0x86
-#define KEY_INTERNATIONAL1 0x87
-#define KEY_INTERNATIONAL2 0x88
-#define KEY_INTERNATIONAL3 0x89
-#define KEY_INTERNATIONAL4 0x8A
-#define KEY_INTERNATIONAL5 0x8B
-#define KEY_INTERNATIONAL6 0x8C
-#define KEY_INTERNATIONAL7 0x8D
-#define KEY_INTERNATIONAL8 0x8E
-#define KEY_INTERNATIONAL9 0x8F
-#define KEY_LANG1 0x90
-#define KEY_LANG2 0x91
-#define KEY_LANG3 0x92
-#define KEY_LANG4 0x93
-#define KEY_LANG5 0x94
-#define KEY_LANG6 0x95
-#define KEY_LANG7 0x96
-#define KEY_LANG8 0x97
-#define KEY_LANG9 0x98
-#define KEY_ALTERNATE_ERASE 0x99
-#define KEY_SYSREQ 0x9A
-#define KEY_CANCEL 0x9B
-#define KEY_CLEAR 0x9C
-#define KEY_PRIOR 0x9D
-#define KEY_RETURN 0x9E
-#define KEY_SEPARATOR 0x9F
-#define KEY_OUT 0xA0
-#define KEY_OPER 0xA1
-#define KEY_CLEAR_AGAIN 0xA2
-#define KEY_CRSEL 0xA3
-#define KEY_EXSEL 0xA4
-#define KEY_KEYPAD_00 0xB0
-#define KEY_KEYPAD_000 0xB1
-#define KEY_THOUSANDS_SEPARATOR 0xB2
-#define KEY_DECIMAL_SEPARATOR 0xB3
-#define KEY_CURRENCY_UNIT 0xB4
-#define KEY_CURRENCY_SUB_UNIT 0xB5
-#define KEY_KEYPAD_OPARENTHESIS 0xB6
-#define KEY_KEYPAD_CPARENTHESIS 0xB7
-#define KEY_KEYPAD_OBRACE 0xB8
-#define KEY_KEYPAD_CBRACE 0xB9
-#define KEY_KEYPAD_TAB 0xBA
-#define KEY_KEYPAD_BACKSPACE 0xBB
-#define KEY_KEYPAD_A 0xBC
-#define KEY_KEYPAD_B 0xBD
-#define KEY_KEYPAD_C 0xBE
-#define KEY_KEYPAD_D 0xBF
-#define KEY_KEYPAD_E 0xC0
-#define KEY_KEYPAD_F 0xC1
-#define KEY_KEYPAD_XOR 0xC2
-#define KEY_KEYPAD_CARET 0xC3
-#define KEY_KEYPAD_PERCENT 0xC4
-#define KEY_KEYPAD_LESS 0xC5
-#define KEY_KEYPAD_GREATER 0xC6
-#define KEY_KEYPAD_AMPERSAND 0xC7
-#define KEY_KEYPAD_LOGICAL_AND 0xC8
-#define KEY_KEYPAD_VERTICAL_BAR 0xC9
-#define KEY_KEYPAD_LOGIACL_OR 0xCA
-#define KEY_KEYPAD_COLON 0xCB
-#define KEY_KEYPAD_NUMBER_SIGN 0xCC
-#define KEY_KEYPAD_SPACE 0xCD
-#define KEY_KEYPAD_AT 0xCE
-#define KEY_KEYPAD_EXCLAMATION_MARK 0xCF
-#define KEY_KEYPAD_MEMORY_STORE 0xD0
-#define KEY_KEYPAD_MEMORY_RECALL 0xD1
-#define KEY_KEYPAD_MEMORY_CLEAR 0xD2
-#define KEY_KEYPAD_MEMORY_ADD 0xD3
-#define KEY_KEYPAD_MEMORY_SUBTRACT 0xD4
-#define KEY_KEYPAD_MEMORY_MULTIPLY 0xD5
-#define KEY_KEYPAD_MEMORY_DIVIDE 0xD6
-#define KEY_KEYPAD_PLUSMINUS 0xD7
-#define KEY_KEYPAD_CLEAR 0xD8
-#define KEY_KEYPAD_CLEAR_ENTRY 0xD9
-#define KEY_KEYPAD_BINARY 0xDA
-#define KEY_KEYPAD_OCTAL 0xDB
-#define KEY_KEYPAD_DECIMAL 0xDC
-#define KEY_KEYPAD_HEXADECIMAL 0xDD
-#define KEY_LEFTCONTROL 0xE0
-#define KEY_LEFTSHIFT 0xE1
-#define KEY_LEFTALT 0xE2
-#define KEY_LEFT_GUI 0xE3
-#define KEY_RIGHTCONTROL 0xE4
-#define KEY_RIGHTSHIFT 0xE5
-#define KEY_RIGHTALT 0xE6
-#define KEY_RIGHT_GUI 0xE7
-
-typedef enum
-{
- KBD_LEFT_CTRL = 0x01,
- KBD_LEFT_SHIFT = 0x02,
- KBD_LEFT_ALT = 0x04,
- KBD_LEFT_GUI = 0x08,
- KBD_RIGHT_CTRL = 0x10,
- KBD_RIGHT_SHIFT = 0x20,
- KBD_RIGHT_ALT = 0x40,
- KBD_RIGHT_GUI = 0x80
-} SpecialKeys;
-
-void key_down(uint8_t* keys, uint8_t key);
-#endif
diff --git a/emb/pastilda/keys/AsciiKeyCodes.h b/emb/pastilda/keys/AsciiKeyCodes.h
new file mode 100644
index 0000000..fb84347
--- /dev/null
+++ b/emb/pastilda/keys/AsciiKeyCodes.h
@@ -0,0 +1,169 @@
+/*
+ * This file is part of the pastilda project.
+ * hosted at http://github.com/thirdpin/pastilda
+ *
+ * Copyright (C) 2016 Third Pin LLC
+ *
+ * Written by:
+ * Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ * Dmitrii Lisin <mrlisdim@ya.ru>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef KEYS_ASCIIKEYCODES_H_
+#define KEYS_ASCIIKEYCODES_H_
+
+#include <cstdint>
+
+namespace Keys {
+
+typedef uint8_t AsciiCodeType;
+
+enum class AsciiCode : AsciiCodeType {
+ NUL = 0x00, // Null char
+ SOH = 0x01, // Start of Heading
+ STX = 0x02, // Start of Text
+ ETX = 0x03, // End of Text
+ EOT = 0x04, // End of Transmission
+ ENQ = 0x05, // Enquiry
+ ACK = 0x06, // Acknowledgment
+ BEL = 0x07, // Bell
+ BACKSPACE = 0x08, // Back Space
+ TAB = 0x09, // Horizontal Tab
+ LF = 0x0A, // Line Feed
+ VTAB = 0x0B, // Vertical Tab
+ FF = 0x0C, // Form Feed
+ CR = 0x0D, // Carriage Return
+ SO = 0x0E, // Shift Out / X-On
+ SI = 0x0F, // Shift In / X-Off
+ DLE = 0x10, // Data Line Escape
+ DC1 = 0x11, // Device Control 1 (oft. XON)
+ DC2 = 0x12, // Device Control 2
+ DC3 = 0x13, // Device Control 3 (oft. XOFF)
+ DC4 = 0x14, // Device Control 4
+ NAK = 0x15, // Negative Acknowledgement
+ SYN = 0x16, // Synchronous Idle
+ ETB = 0x17, // End of Transmit Block
+ CAN = 0x18, // Cancel
+ EM = 0x19, // End of Medium
+ SUB = 0x1A, // Substitute
+ ESC = 0x1B, // Escape
+ FS = 0x1C, // File Separator
+ GS = 0x1D, // Group Separator
+ RS = 0x1E, // Record Separator
+ US = 0x1F, // Unit Separator
+ SPACE = 0x20, // , Space
+ EXCLAMATION_MARK = 0x21, // !, Exclamation mark
+ DOUBLE_QUOTES = 0x22, // ", Double quotes (or speech marks)
+ NUMBER = 0x23, // #, Number
+ DOLLAR = 0x24, // $, Dollar
+ PERCENT = 0x25, // %, Percent
+ AMPERSAND = 0x26, // &, Ampersand
+ SINGLE_QUOTE = 0x27, // ', Single quote
+ OPEN_PARENTHESIS = 0x28, // (, Open parenthesis (or open bracket)
+ CLOSE_PARENTHESIS = 0x29, // ), Close parenthesis (or close bracket)
+ ASTERISK = 0x2A, // *, Asterisk
+ PLUS = 0x2B, // +, Plus
+ COMMA = 0x2C, // ,, Comma
+ HYPHEN = 0x2D, // -, Hyphen
+ PERIOD_OR_DOT = 0x2E, // ., Period, dot or full stop
+ SLASH_OR_DIVIDE = 0x2F, // /, Slash or divide
+ ZERO = 0x30, // 0, Zero
+ ONE = 0x31, // 1, One
+ TWO = 0x32, // 2, Two
+ THREE = 0x33, // 3, Three
+ FOUR = 0x34, // 4, Four
+ FIVE = 0x35, // 5, Five
+ SIX = 0x36, // 6, Six
+ SEVEN = 0x37, // 7, Seven
+ EIGHT = 0x38, // 8, Eight
+ NINE = 0x39, // 9, Nine
+ COLON = 0x3A, // :, Colon
+ SEMICOLON = 0x3B, // ;, Semicolon
+ LESS_THAN = 0x3C, // <, Less than (or open angled bracket)
+ EQUALS = 0x3D, // =, Equals
+ GREATER_THAN = 0x3E, // >, Greater than (or close angled bracket)
+ QUESTION_MARK = 0x3F, // ?, Question mark
+ AT_SYMBOL = 0x40, // @, At symbol
+ UPPERCASE_A = 0x41, // A, Uppercase A
+ UPPERCASE_B = 0x42, // B, Uppercase B
+ UPPERCASE_C = 0x43, // C, Uppercase C
+ UPPERCASE_D = 0x44, // D, Uppercase D
+ UPPERCASE_E = 0x45, // E, Uppercase E
+ UPPERCASE_F = 0x46, // F, Uppercase F
+ UPPERCASE_G = 0x47, // G, Uppercase G
+ UPPERCASE_H = 0x48, // H, Uppercase H
+ UPPERCASE_I = 0x49, // I, Uppercase I
+ UPPERCASE_J = 0x4A, // J, Uppercase J
+ UPPERCASE_K = 0x4B, // K, Uppercase K
+ UPPERCASE_L = 0x4C, // L, Uppercase L
+ UPPERCASE_M = 0x4D, // M, Uppercase M
+ UPPERCASE_N = 0x4E, // N, Uppercase N
+ UPPERCASE_O = 0x4F, // O, Uppercase O
+ UPPERCASE_P = 0x50, // P, Uppercase P
+ UPPERCASE_Q = 0x51, // Q, Uppercase Q
+ UPPERCASE_R = 0x52, // R, Uppercase R
+ UPPERCASE_S = 0x53, // S, Uppercase S
+ UPPERCASE_T = 0x54, // T, Uppercase T
+ UPPERCASE_U = 0x55, // U, Uppercase U
+ UPPERCASE_V = 0x56, // V, Uppercase V
+ UPPERCASE_W = 0x57, // W, Uppercase W
+ UPPERCASE_X = 0x58, // X, Uppercase X
+ UPPERCASE_Y = 0x59, // Y, Uppercase Y
+ UPPERCASE_Z = 0x5A, // Z, Uppercase Z
+ OPENING_BRACKET = 0x5B, // [, Opening bracket
+ BACKSLASH = 0x5C, // \, Backslash
+ CLOSING_BRACKET = 0x5D, // ], Closing bracket
+ CARET = 0x5E, // ^, Caret - circumflex
+ UNDERSCORE = 0x5F, // _, Underscore
+ GRAVE_ACCENT = 0x60, // `, Grave accent
+ LOWERCASE_A = 0x61, // a, Lowercase a
+ LOWERCASE_B = 0x62, // b, Lowercase b
+ LOWERCASE_C = 0x63, // c, Lowercase c
+ LOWERCASE_D = 0x64, // d, Lowercase d
+ LOWERCASE_E = 0x65, // e, Lowercase e
+ LOWERCASE_F = 0x66, // f, Lowercase f
+ LOWERCASE_G = 0x67, // g, Lowercase g
+ LOWERCASE_H = 0x68, // h, Lowercase h
+ LOWERCASE_I = 0x69, // i, Lowercase i
+ LOWERCASE_J = 0x6A, // j, Lowercase j
+ LOWERCASE_K = 0x6B, // k, Lowercase k
+ LOWERCASE_L = 0x6C, // l, Lowercase l
+ LOWERCASE_M = 0x6D, // m, Lowercase m
+ LOWERCASE_N = 0x6E, // n, Lowercase n
+ LOWERCASE_O = 0x6F, // o, Lowercase o
+ LOWERCASE_P = 0x70, // p, Lowercase p
+ LOWERCASE_Q = 0x71, // q, Lowercase q
+ LOWERCASE_R = 0x72, // r, Lowercase r
+ LOWERCASE_S = 0x73, // s, Lowercase s
+ LOWERCASE_T = 0x74, // t, Lowercase t
+ LOWERCASE_U = 0x75, // u, Lowercase u
+ LOWERCASE_V = 0x76, // v, Lowercase v
+ LOWERCASE_W = 0x77, // w, Lowercase w
+ LOWERCASE_X = 0x78, // x, Lowercase x
+ LOWERCASE_Y = 0x79, // y, Lowercase y
+ LOWERCASE_Z = 0x7A, // z, Lowercase z
+ OPENING_BRACE = 0x7B, // {, Opening brace
+ VERTICAL_BAR = 0x7C, // |, Vertical bar
+ CLOSING_BRACE = 0x7D, // }, Closing brace
+ TILDE_OR_EQUIVALENCY_SIGN = 0x7E, // ~, Equivalency sign - tilde
+ DELETE = 0x7F // , Delete
+};
+
+}
+
+
+
+#endif /* KEYS_ASCIIKEYCODES_H_ */
diff --git a/emb/pastilda/keys/Key.cpp b/emb/pastilda/keys/Key.cpp
new file mode 100644
index 0000000..f7b304d
--- /dev/null
+++ b/emb/pastilda/keys/Key.cpp
@@ -0,0 +1,653 @@
+/*
+ * This file is part of the pastilda project.
+ * hosted at http://github.com/thirdpin/pastilda
+ *
+ * Copyright (C) 2016 Third Pin LLC
+ *
+ * Written by:
+ * Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ * Dmitrii Lisin <mrlisdim@ya.ru>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <UsbKeyCodes.h>
+#include <AsciiKeyCodes.h>
+#include <Key.h>
+
+namespace {
+using namespace Keys;
+
+static AsciiCode usbKeyToAsciiCode[128] = {
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::UPPERCASE_A,
+ AsciiCode::UPPERCASE_B,
+ AsciiCode::UPPERCASE_C,
+ AsciiCode::UPPERCASE_D,
+ AsciiCode::UPPERCASE_E,
+ AsciiCode::UPPERCASE_F,
+ AsciiCode::UPPERCASE_G,
+ AsciiCode::UPPERCASE_H,
+ AsciiCode::UPPERCASE_I,
+ AsciiCode::UPPERCASE_J,
+ AsciiCode::UPPERCASE_K,
+ AsciiCode::UPPERCASE_L,
+ AsciiCode::UPPERCASE_M,
+ AsciiCode::UPPERCASE_N,
+ AsciiCode::UPPERCASE_O,
+ AsciiCode::UPPERCASE_P,
+ AsciiCode::UPPERCASE_Q,
+ AsciiCode::UPPERCASE_R,
+ AsciiCode::UPPERCASE_S,
+ AsciiCode::UPPERCASE_T,
+ AsciiCode::UPPERCASE_U,
+ AsciiCode::UPPERCASE_V,
+ AsciiCode::UPPERCASE_W,
+ AsciiCode::UPPERCASE_X,
+ AsciiCode::UPPERCASE_Y,
+ AsciiCode::UPPERCASE_Z,
+ AsciiCode::EXCLAMATION_MARK,
+ AsciiCode::AT_SYMBOL,
+ AsciiCode::NUMBER,
+ AsciiCode::DOLLAR,
+ AsciiCode::PERCENT,
+ AsciiCode::CARET,
+ AsciiCode::AMPERSAND,
+ AsciiCode::ASTERISK,
+ AsciiCode::OPEN_PARENTHESIS,
+ AsciiCode::CLOSE_PARENTHESIS,
+ AsciiCode::LF,
+ AsciiCode::ESC,
+ AsciiCode::BACKSPACE,
+ AsciiCode::TAB,
+ AsciiCode::SPACE,
+ AsciiCode::UNDERSCORE,
+ AsciiCode::EQUALS,
+ AsciiCode::OPENING_BRACKET,
+ AsciiCode::CLOSING_BRACKET,
+ AsciiCode::BACKSLASH,
+ AsciiCode::NUL, // KEY_NONUS_NUMBER_SIGN_TILDE
+ AsciiCode::SEMICOLON,
+ AsciiCode::SINGLE_QUOTE,
+ AsciiCode::GRAVE_ACCENT,
+ AsciiCode::COMMA,
+ AsciiCode::PERIOD_OR_DOT,
+ AsciiCode::SLASH_OR_DIVIDE,
+ AsciiCode::NUL, // Caps Lock
+ AsciiCode::NUL, // F1
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL, // F12
+ AsciiCode::NUL, // KEY_PRINTSCREEN
+ AsciiCode::NUL, // KEY_SCROLL_LOCK
+ AsciiCode::NUL, // KEY_PAUSE
+ AsciiCode::NUL, // KEY_INSERT
+ AsciiCode::NUL, // KEY_HOME
+ AsciiCode::NUL, // KEY_PAGEUP
+ AsciiCode::DELETE,
+ AsciiCode::NUL, // KEY_END1
+ AsciiCode::NUL, // KEY_PAGEDOWN
+ AsciiCode::NUL, // KEY_RIGHTARROW
+ AsciiCode::NUL, // KEY_LEFTARROW
+ AsciiCode::NUL, // KEY_DOWNARROW
+ AsciiCode::NUL, // KEY_UPARROW
+ AsciiCode::NUL, // KEY_KEYPAD_NUM_LOCK_AND_CLEAR
+ AsciiCode::SLASH_OR_DIVIDE,
+ AsciiCode::ASTERISK,
+ AsciiCode::HYPHEN,
+ AsciiCode::PLUS,
+ AsciiCode::LF,
+ AsciiCode::ONE,
+ AsciiCode::TWO,
+ AsciiCode::THREE,
+ AsciiCode::FOUR,
+ AsciiCode::FIVE,
+ AsciiCode::SIX,
+ AsciiCode::SEVEN,
+ AsciiCode::EIGHT,
+ AsciiCode::NINE,
+ AsciiCode::ZERO,
+ AsciiCode::PERIOD_OR_DOT,
+ AsciiCode::SLASH_OR_DIVIDE,
+ AsciiCode::NUL, // KEY_APPLICATION
+ AsciiCode::ASTERISK,
+ AsciiCode::EQUALS,
+ AsciiCode::NUL, // F13
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL, // F24
+ AsciiCode::NUL, // KEY_EXECUTE
+ AsciiCode::NUL, // KEY_HELP
+ AsciiCode::NUL, // KEY_MENU
+ AsciiCode::NUL, // KEY_SELECT
+ AsciiCode::NUL, // KEY_STOP
+ AsciiCode::NUL, // KEY_AGAIN
+ AsciiCode::NUL, // KEY_UNDO
+ AsciiCode::NUL, // KEY_CUT
+ AsciiCode::NUL, // KEY_COPY
+ AsciiCode::NUL, // KEY_PASTE
+ AsciiCode::NUL // KEY_FIND
+};
+
+constexpr static size_t SHIFT_FOR_SHIFTED_ASCII_CODES = 0x21;
+static AsciiCode asciiShifted[128 - SHIFT_FOR_SHIFTED_ASCII_CODES] = {
+ AsciiCode::NUL, // EXCLAMATION_MARK
+ AsciiCode::NUL, // DOUBLE_QUOTES
+ AsciiCode::NUL, // NUMBER
+ AsciiCode::NUL, // DOLLAR
+ AsciiCode::NUL, // PERCENT
+ AsciiCode::NUL, // AMPERSAND
+ AsciiCode::DOUBLE_QUOTES, // SINGLE_QUOTE
+ AsciiCode::NUL, // OPEN_PARENTHESIS
+ AsciiCode::NUL, // CLOSE_PARENTHESIS
+ AsciiCode::NUL, // ASTERISK
+ AsciiCode::NUL, // PLUS
+ AsciiCode::LESS_THAN, // COMMA
+ AsciiCode::UNDERSCORE, // HYPHEN
+ AsciiCode::GREATER_THAN, // PERIOD_OR_DOT
+ AsciiCode::QUESTION_MARK, // SLASH_OR_DIVIDE
+ AsciiCode::CLOSE_PARENTHESIS, // ZERO
+ AsciiCode::EXCLAMATION_MARK, // ONE
+ AsciiCode::AT_SYMBOL, // TWO
+ AsciiCode::NUMBER, // THREE
+ AsciiCode::DOLLAR, // FOUR
+ AsciiCode::PERCENT, // FIVE
+ AsciiCode::CARET, // SIX
+ AsciiCode::AMPERSAND, // SEVEN
+ AsciiCode::ASTERISK, // EIGHT
+ AsciiCode::OPEN_PARENTHESIS, // NINE
+ AsciiCode::NUL, // COLON
+ AsciiCode::COLON, // SEMICOLON
+ AsciiCode::NUL, // LESS_THAN
+ AsciiCode::PLUS, // EQUALS
+ AsciiCode::NUL, // GREATER_THAN
+ AsciiCode::NUL, // QUESTION_MARK
+ AsciiCode::NUL, // AT_SYMBOL
+ AsciiCode::NUL, // UPPERCASE_A
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL, // UPPERCASE_Z
+ AsciiCode::OPENING_BRACE, // OPENING_BRACKET
+ AsciiCode::VERTICAL_BAR, // BACKSLASH
+ AsciiCode::CLOSING_BRACE, // CLOSING_BRACKET
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::TILDE_OR_EQUIVALENCY_SIGN, // GRAVE_ACCENT
+ AsciiCode::UPPERCASE_A, // LOWERCASE_A
+ AsciiCode::UPPERCASE_B,
+ AsciiCode::UPPERCASE_C,
+ AsciiCode::UPPERCASE_D,
+ AsciiCode::UPPERCASE_E,
+ AsciiCode::UPPERCASE_F,
+ AsciiCode::UPPERCASE_G,
+ AsciiCode::UPPERCASE_H,
+ AsciiCode::UPPERCASE_I,
+ AsciiCode::UPPERCASE_J,
+ AsciiCode::UPPERCASE_K,
+ AsciiCode::UPPERCASE_L,
+ AsciiCode::UPPERCASE_M,
+ AsciiCode::UPPERCASE_N,
+ AsciiCode::UPPERCASE_O,
+ AsciiCode::UPPERCASE_P,
+ AsciiCode::UPPERCASE_Q,
+ AsciiCode::UPPERCASE_R,
+ AsciiCode::UPPERCASE_S,
+ AsciiCode::UPPERCASE_T,
+ AsciiCode::UPPERCASE_U,
+ AsciiCode::UPPERCASE_V,
+ AsciiCode::UPPERCASE_W,
+ AsciiCode::UPPERCASE_X,
+ AsciiCode::UPPERCASE_Y,
+ AsciiCode::UPPERCASE_Z, // LOWERCASE_Z
+ AsciiCode::NUL, // OPENING_BRACE
+ AsciiCode::NUL, // VERTICAL_BAR
+ AsciiCode::NUL, // CLOSING_BRACE
+ AsciiCode::NUL, // TILDE_OR_EQUIVALENCY_SIGN
+ AsciiCode::NUL // DELETE
+};
+
+constexpr static size_t SHIFT_FOR_SHIFTED_BACK_ASCII_CODES = 0x21;
+static AsciiCode asciiShiftedBack[128 - SHIFT_FOR_SHIFTED_BACK_ASCII_CODES] = {
+ AsciiCode::ONE, // EXCLAMATION_MARK
+ AsciiCode::SINGLE_QUOTE, // DOUBLE_QUOTES
+ AsciiCode::THREE, // NUMBER
+ AsciiCode::FOUR, // DOLLAR
+ AsciiCode::FIVE, // PERCENT
+ AsciiCode::SEVEN, // AMPERSAND
+ AsciiCode::NUL, // SINGLE_QUOTE
+ AsciiCode::NINE, // OPEN_PARENTHESIS
+ AsciiCode::ZERO, // CLOSE_PARENTHESIS
+ AsciiCode::EIGHT, // ASTERISK
+ AsciiCode::EQUALS, // PLUS
+ AsciiCode::NUL, // COMMA
+ AsciiCode::NUL, // HYPHEN
+ AsciiCode::NUL, // PERIOD_OR_DOT
+ AsciiCode::NUL, // SLASH_OR_DIVIDE
+ AsciiCode::NUL, // ZERO
+ AsciiCode::NUL, // ONE
+ AsciiCode::NUL, // TWO
+ AsciiCode::NUL, // THREE
+ AsciiCode::NUL, // FOUR
+ AsciiCode::NUL, // FIVE
+ AsciiCode::NUL, // SIX
+ AsciiCode::NUL, // SEVEN
+ AsciiCode::NUL, // EIGHT
+ AsciiCode::NUL, // NINE
+ AsciiCode::SEMICOLON, // COLON
+ AsciiCode::NUL, // SEMICOLON
+ AsciiCode::COMMA, // LESS_THAN
+ AsciiCode::NUL, // EQUALS
+ AsciiCode::PERIOD_OR_DOT, // GREATER_THAN
+ AsciiCode::SLASH_OR_DIVIDE, // QUESTION_MARK
+ AsciiCode::TWO, // AT_SYMBOL
+ AsciiCode::LOWERCASE_A, // UPPERCASE_A
+ AsciiCode::LOWERCASE_B,
+ AsciiCode::LOWERCASE_C,
+ AsciiCode::LOWERCASE_D,
+ AsciiCode::LOWERCASE_E,
+ AsciiCode::LOWERCASE_F,
+ AsciiCode::LOWERCASE_G,
+ AsciiCode::LOWERCASE_H,
+ AsciiCode::LOWERCASE_I,
+ AsciiCode::LOWERCASE_J,
+ AsciiCode::LOWERCASE_K,
+ AsciiCode::LOWERCASE_L,
+ AsciiCode::LOWERCASE_M,
+ AsciiCode::LOWERCASE_N,
+ AsciiCode::LOWERCASE_O,
+ AsciiCode::LOWERCASE_P,
+ AsciiCode::LOWERCASE_Q,
+ AsciiCode::LOWERCASE_R,
+ AsciiCode::LOWERCASE_S,
+ AsciiCode::LOWERCASE_T,
+ AsciiCode::LOWERCASE_U,
+ AsciiCode::LOWERCASE_V,
+ AsciiCode::LOWERCASE_W,
+ AsciiCode::LOWERCASE_X,
+ AsciiCode::LOWERCASE_Y,
+ AsciiCode::LOWERCASE_Z, // UPPERCASE_Z
+ AsciiCode::NUL, // OPENING_BRACKET
+ AsciiCode::NUL, // BACKSLASH
+ AsciiCode::NUL, // CLOSING_BRACKET
+ AsciiCode::SIX, // CARET
+ AsciiCode::HYPHEN, // UNDERSCORE
+ AsciiCode::NUL, // GRAVE_ACCENT
+ AsciiCode::NUL, // LOWERCASE_A
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL,
+ AsciiCode::NUL, // LOWERCASE_Z
+ AsciiCode::OPENING_BRACKET, // OPENING_BRACE
+ AsciiCode::SLASH_OR_DIVIDE, // VERTICAL_BAR
+ AsciiCode::CLOSING_BRACKET, // CLOSING_BRACE
+ AsciiCode::GRAVE_ACCENT, // TILDE_OR_EQUIVALENCY_SIGN
+ AsciiCode::NUL // DELETE
+};
+
+static UsbKey asciiCodeToUsbKey[128] = {
+ UsbKey::NOT_A_KEY, // 0x00 Null
+ UsbKey::NOT_A_KEY, // 0x01
+ UsbKey::NOT_A_KEY, // 0x02
+ UsbKey::NOT_A_KEY, // 0x03
+ UsbKey::NOT_A_KEY, // 0x04
+ UsbKey::NOT_A_KEY, // 0x05
+ UsbKey::NOT_A_KEY, // 0x06
+ UsbKey::NOT_A_KEY, // 0x07
+ UsbKey::KEY_BACKSPACE, // 0x08 Backspace
+ UsbKey::KEY_TAB, // 0x09 Horizontal Tab
+ UsbKey::KEY_RETURN, // 0x0A Line Feed
+ UsbKey::NOT_A_KEY, // 0x0B
+ UsbKey::NOT_A_KEY, // 0x0C
+ UsbKey::KEY_RETURN, // 0x0D Carriage return
+ UsbKey::NOT_A_KEY, // 0x0E
+ UsbKey::NOT_A_KEY, // 0x0F
+ UsbKey::NOT_A_KEY, // 0x10
+ UsbKey::NOT_A_KEY, // 0x11
+ UsbKey::NOT_A_KEY, // 0x12
+ UsbKey::NOT_A_KEY, // 0x13
+ UsbKey::NOT_A_KEY, // 0x14
+ UsbKey::NOT_A_KEY, // 0x15
+ UsbKey::NOT_A_KEY, // 0x16
+ UsbKey::NOT_A_KEY, // 0x17
+ UsbKey::NOT_A_KEY, // 0x18
+ UsbKey::NOT_A_KEY, // 0x19
+ UsbKey::NOT_A_KEY, // 0x1A
+ UsbKey::KEY_ESCAPE, // 0x1B Escape
+ UsbKey::NOT_A_KEY, // 0x1C
+ UsbKey::NOT_A_KEY, // 0x1D
+ UsbKey::NOT_A_KEY, // 0x1E
+ UsbKey::NOT_A_KEY, // 0x1F
+ UsbKey::KEY_SPACEBAR, // 0x20
+ UsbKey::KEY_1_EXCLAMATION_MARK, // 0x21 !
+ UsbKey::KEY_2_AT, // 0x22 "
+ UsbKey::KEY_3_NUMBER_SIGN, // 0x23 #
+ UsbKey::KEY_4_DOLLAR, // 0x24 $
+ UsbKey::KEY_5_PERCENT, // 0x25 %
+ UsbKey::KEY_7_AMPERSAND, // 0x26 &
+ UsbKey::KEY_SINGLE_AND_DOUBLE_QUOTE, // 0x27 '
+ UsbKey::KEY_9_OPARENTHESIS, // 0x28 (
+ UsbKey::KEY_0_CPARENTHESIS, // 0x29 )
+ UsbKey::KEY_8_ASTERISK, // 0x2A *
+ UsbKey::KEY_EQUAL_PLUS, // 0x2B +
+ UsbKey::KEY_COMMA_AND_LESS, // 0x2C ,
+ UsbKey::KEY_MINUS_UNDERSCORE, // 0x2D -
+ UsbKey::KEY_DOT_GREATER, // 0x2E .
+ UsbKey::KEY_SLASH_QUESTION, // 0x2F /
+ UsbKey::KEY_0_CPARENTHESIS, // 0x30 0
+ UsbKey::KEY_1_EXCLAMATION_MARK, // 0x31 1
+ UsbKey::KEY_2_AT, // 0x32 2
+ UsbKey::KEY_3_NUMBER_SIGN, // 0x33 3
+ UsbKey::KEY_4_DOLLAR, // 0x34 4
+ UsbKey::KEY_5_PERCENT, // 0x35 5
+ UsbKey::KEY_6_CARET, // 0x36 6
+ UsbKey::KEY_7_AMPERSAND, // 0x37 7
+ UsbKey::KEY_8_ASTERISK, // 0x38 8
+ UsbKey::KEY_9_OPARENTHESIS, // 0x39 9
+ UsbKey::KEY_SEMICOLON_COLON, // 0x3A :
+ UsbKey::KEY_SEMICOLON_COLON, // 0x3B ;
+ UsbKey::KEY_COMMA_AND_LESS, // 0x3C <
+ UsbKey::KEY_EQUAL_PLUS, // 0x3D =
+ UsbKey::KEY_DOT_GREATER, // 0x3E >
+ UsbKey::KEY_SLASH_QUESTION, // 0x3F ?
+ UsbKey::KEY_2_AT, // 0x40 @
+ UsbKey::KEY_A, // 0x41 A
+ UsbKey::KEY_B, // 0x42 B
+ UsbKey::KEY_C, // 0x43 C
+ UsbKey::KEY_D, // 0x44 D
+ UsbKey::KEY_E, // 0x45 E
+ UsbKey::KEY_F, // 0x46 F
+ UsbKey::KEY_G, // 0x47 G
+ UsbKey::KEY_H, // 0x48 H
+ UsbKey::KEY_I, // 0x49 I
+ UsbKey::KEY_J, // 0x4A J
+ UsbKey::KEY_K, // 0x4B K
+ UsbKey::KEY_L, // 0x4C L
+ UsbKey::KEY_M, // 0x4D M
+ UsbKey::KEY_N, // 0x4E N
+ UsbKey::KEY_O, // 0x4F O
+ UsbKey::KEY_P, // 0x50 P
+ UsbKey::KEY_Q, // 0x51 Q
+ UsbKey::KEY_R, // 0x52 R
+ UsbKey::KEY_S, // 0x53 S
+ UsbKey::KEY_T, // 0x55 T
+ UsbKey::KEY_U, // 0x55 U
+ UsbKey::KEY_V, // 0x56 V
+ UsbKey::KEY_W, // 0x57 W
+ UsbKey::KEY_X, // 0x58 X
+ UsbKey::KEY_Y, // 0x59 Y
+ UsbKey::KEY_Z, // 0x5A Z
+ UsbKey::KEY_OBRACKET_AND_OBRACE, // 0x5B [
+ UsbKey::KEY_BACKSLASH_VERTICAL_BAR, // 0x5C '\'
+ UsbKey::KEY_CBRACKET_AND_CBRACE, // 0x5D ]
+ UsbKey::KEY_6_CARET, // 0x5E ^
+ UsbKey::KEY_MINUS_UNDERSCORE, // 0x5F _
+ UsbKey::KEY_GRAVE_ACCENT_AND_TILDE, // 0x60 `
+ UsbKey::KEY_A, // 0x61 a
+ UsbKey::KEY_B, // 0x62 b
+ UsbKey::KEY_C, // 0x63 c
+ UsbKey::KEY_D, // 0x66 d
+ UsbKey::KEY_E, // 0x65 e
+ UsbKey::KEY_F, // 0x66 f
+ UsbKey::KEY_G, // 0x67 g
+ UsbKey::KEY_H, // 0x68 h
+ UsbKey::KEY_I, // 0x69 i
+ UsbKey::KEY_J, // 0x6A j
+ UsbKey::KEY_K, // 0x6B k
+ UsbKey::KEY_L, // 0x6C l
+ UsbKey::KEY_M, // 0x6D m
+ UsbKey::KEY_N, // 0x6E n
+ UsbKey::KEY_O, // 0x6F o
+ UsbKey::KEY_P, // 0x70 p
+ UsbKey::KEY_Q, // 0x71 q
+ UsbKey::KEY_R, // 0x72 r
+ UsbKey::KEY_S, // 0x73 s
+ UsbKey::KEY_T, // 0x75 t
+ UsbKey::KEY_U, // 0x75 u
+ UsbKey::KEY_V, // 0x76 v
+ UsbKey::KEY_W, // 0x77 w
+ UsbKey::KEY_X, // 0x78 x
+ UsbKey::KEY_Y, // 0x79 y
+ UsbKey::KEY_Z, // 0x7A z
+ UsbKey::KEY_OBRACKET_AND_OBRACE, // 0x7B {
+ UsbKey::KEY_BACKSLASH_VERTICAL_BAR, // 0x7C |
+ UsbKey::KEY_CBRACKET_AND_CBRACE, // 0x7D }
+ UsbKey::KEY_GRAVE_ACCENT_AND_TILDE, // 0x7E ~
+ UsbKey::KEY_DELETE // 0x7F Delete
+};
+
+}
+
+namespace Keys {
+
+AsciiCode getAsciiByUsbKey(UsbKey code)
+{
+ return usbKeyToAsciiCode[static_cast<AsciiCodeType>(code)];
+}
+
+UsbKey getUsbKeyByAscii(AsciiCode code)
+{
+ return asciiCodeToUsbKey[static_cast<AsciiCodeType>(code)];
+}
+
+AsciiCode getAsciiShifted(AsciiCode code)
+{
+ return asciiShifted[static_cast<AsciiCodeType>(code) - SHIFT_FOR_SHIFTED_ASCII_CODES];
+}
+
+AsciiCode getAsciiBackShifted(AsciiCode code)
+{
+ return asciiShiftedBack[static_cast<AsciiCodeType>(code) - SHIFT_FOR_SHIFTED_BACK_ASCII_CODES];
+}
+
+bool isAsciiShifted(AsciiCode code)
+{
+ return (getAsciiBackShifted(code) != AsciiCode::NUL);
+}
+
+Key::Key():
+ _usbKey(UsbKey::NOT_A_KEY),
+ _asciiCode(AsciiCode::NUL),
+ _keyType(KeyType::SYBMOL)
+{ }
+
+Key::Key(UsbKeyCodeType key, UsbKeyCodeType modifier)
+{
+ set(key, modifier);
+}
+
+Key::Key(UsbKey key, UsbSpecialKeySequence modifier)
+{
+ set(key, modifier);
+}
+
+Key::Key(AsciiCodeType code)
+{
+ set(code);
+}
+
+Key::Key(AsciiCode code)
+{
+ set(static_cast<AsciiCodeType>(code));
+}
+
+Key::Key(UsbKeyCodeType key, UsbSpecialKey modifier)
+{
+ set(key, static_cast<UsbKeyCodeType>(modifier));
+}
+
+Key::Key(UsbKey key, UsbKeyCodeType modifier)
+{
+ set(static_cast<UsbKeyCodeType>(key), modifier);
+}
+
+Key::Key(UsbKey key, UsbSpecialKey modifier)
+{
+ set(key, modifier);
+}
+
+Key::Key(UsbKey key)
+{
+ set(key, UsbSpecialKey::NO_KEY);
+}
+
+Key::~Key()
+{ }
+
+void Key::set(AsciiCodeType code)
+{
+ _asciiCode = static_cast<AsciiCode>(code);
+ _usbKey = getUsbKeyByAscii(_asciiCode);
+ _usbKeyModifier.clear();
+
+ if (isAsciiShifted(_asciiCode)) {
+ _usbKeyModifier = UsbSpecialKey::LEFT_SHIFT;
+ _usbKey = getUsbKeyByAscii(
+ getAsciiBackShifted(_asciiCode)
+ );
+ }
+
+ _updateKeyType();
+}
+
+void Key::set(UsbKey key, UsbSpecialKey modifier)
+{
+ set(
+ static_cast<UsbKeyCodeType>(key),
+ static_cast<UsbKeyCodeType>(modifier)
+ );
+}
+
+void Key::set(UsbKeyCodeType key, UsbKeyCodeType modifier)
+{
+ _usbKey = static_cast<UsbKey>(key);
+ _usbKeyModifier = modifier;
+
+ _asciiCode = getAsciiByUsbKey(_usbKey);
+
+ _checkAsciiShifted();
+
+ _updateKeyType();
+}
+
+void Key::set(UsbKey key, UsbSpecialKeySequence modifier)
+{
+ _usbKey = key;
+ _usbKeyModifier = modifier;
+
+ _asciiCode = getAsciiByUsbKey(_usbKey);
+
+ _checkAsciiShifted();
+
+ _updateKeyType();
+}
+
+void Key::_checkAsciiShifted()
+{
+ if (_asciiCode != AsciiCode::NUL) {
+ bool usbModifierIsShift =
+ (_usbKeyModifier == UsbSpecialKey::LEFT_SHIFT ||
+ _usbKeyModifier == UsbSpecialKey::RIGHT_SHIFT);
+
+ if (usbModifierIsShift) {
+ if (!isAsciiShifted(_asciiCode)) {
+ _asciiCode = getAsciiShifted(_asciiCode);
+ }
+ }
+ else {
+ if (isAsciiShifted(_asciiCode)) {
+ _asciiCode = getAsciiBackShifted(_asciiCode);
+ }
+ }
+ }
+}
+
+void Key::_updateKeyType()
+{
+ if (_usbKey == UsbKey::KEY_RIGHTARROW ||
+ _usbKey == UsbKey::KEY_LEFTARROW ||
+ _usbKey == UsbKey::KEY_UPARROW ||
+ _usbKey == UsbKey::KEY_DOWNARROW ||
+ _usbKey == UsbKey::KEY_ENTER ||
+ _usbKey == UsbKey::KEY_ESCAPE)
+ {
+ _keyType = CONTROL;
+ }
+ else {
+ _keyType = SYBMOL;
+ }
+}
+
+} /* namespace Keys */
diff --git a/emb/pastilda/keys/Key.h b/emb/pastilda/keys/Key.h
new file mode 100644
index 0000000..d192197
--- /dev/null
+++ b/emb/pastilda/keys/Key.h
@@ -0,0 +1,155 @@
+/*
+ * This file is part of the pastilda project.
+ * hosted at http://github.com/thirdpin/pastilda
+ *
+ * Copyright (C) 2016 Third Pin LLC
+ *
+ * Written by:
+ * Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ * Dmitrii Lisin <mrlisdim@ya.ru>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef KEYS_KEY_H_
+#define KEYS_KEY_H_
+
+#include <cstdint>
+
+#include <UsbKeyCodes.h>
+#include <AsciiKeyCodes.h>
+
+namespace Keys {
+
+AsciiCode getAsciiByUsbKey(UsbKey code);
+UsbKey getUsbKeyByAscii(AsciiCode code);
+
+AsciiCode getAsciiShifted(AsciiCode code);
+AsciiCode getAsciiBackShifted(AsciiCode code);
+bool isAsciiShifted(AsciiCode code);
+
+class Key {
+public:
+
+ enum KeyType {
+ CONTROL,
+ SYBMOL
+ };
+
+ Key();
+ Key(UsbKey key);
+ Key(UsbKeyCodeType key, UsbKeyCodeType modifier);
+ Key(UsbKeyCodeType key, UsbSpecialKey modifier);
+ Key(UsbKey key, UsbKeyCodeType modifier);
+ Key(UsbKey key, UsbSpecialKeySequence modifier);
+ Key(UsbKey key, UsbSpecialKey modifier);
+ Key(AsciiCodeType code);
+ Key(AsciiCode code);
+ ~Key();
+
+ void set(UsbKeyCodeType key, UsbKeyCodeType modifier);
+ void set(UsbKey key, UsbSpecialKeySequence modifier);
+ void set(UsbKey key, UsbSpecialKey modifier);
+ void set(AsciiCodeType code);
+
+ UsbKeyCodeType getUsbKeyCode() const {
+ return static_cast<UsbKeyCodeType>(_usbKey);
+ }
+
+ UsbKey getUsbKey() const {
+ return _usbKey;
+ }
+
+ UsbSpecialKeySequence getUsbKeyModifier() const {
+ return _usbKeyModifier;
+ }
+
+ UsbKeyCodeType getUsbKeyModifierMask() {
+ return _usbKeyModifier.getMask();
+ }
+
+ AsciiCodeType getAsciiCode() const {
+ return static_cast<AsciiCodeType>(_asciiCode);
+ }
+
+ AsciiCode getAscii() const {
+ return _asciiCode;
+ }
+
+ bool isControl() const {
+ return (_keyType == CONTROL);
+ }
+
+ bool isShifted() const {
+ return isAsciiShifted(_asciiCode);
+ }
+
+ bool operator==(Key& rhs) const {
+ return (rhs._usbKey == _usbKey) &&
+ (rhs._usbKeyModifier == _usbKeyModifier);
+ }
+
+ bool operator!=(Key& rhs) const {
+ return !((rhs._usbKey == _usbKey) &&
+ (rhs._usbKeyModifier == _usbKeyModifier));
+ }
+
+ friend bool operator==(Key& lhs, UsbKey rhs) {
+ return (lhs._usbKey == rhs);
+ }
+
+ friend bool operator!=(Key& lhs, UsbKey rhs) {
+ return !(lhs._usbKey == rhs);
+ }
+
+ friend bool operator==(UsbKey rhs, Key& lhs) {
+ return (lhs._usbKey == rhs);
+ }
+
+ friend bool operator==(Key& lhs, AsciiCode rhs) {
+ return (lhs._asciiCode == rhs);
+ }
+
+ friend bool operator==(AsciiCode rhs, Key& lhs) {
+ return (lhs._asciiCode == rhs);
+ }
+
+ Key& operator=(const Key& rhs) {
+ _asciiCode = rhs.getAscii();
+ _usbKey = rhs.getUsbKey();
+ _usbKeyModifier = rhs.getUsbKeyModifier();
+ _updateKeyType();
+ return *this;
+ }
+
+ Key& operator=(const UsbKey& rhs) {
+ set(rhs, UsbSpecialKey::NO_KEY);
+ return *this;
+ }
+
+private:
+ UsbSpecialKeySequence _usbKeyModifier;
+ UsbKey _usbKey;
+
+ AsciiCode _asciiCode;
+
+ KeyType _keyType;
+
+ void _checkAsciiShifted();
+ void _updateKeyType();
+};
+
+} /* namespace Keys */
+
+#endif /* KEYS_KEY_H_ */
diff --git a/emb/pastilda/keys/UsbKeyCodes.h b/emb/pastilda/keys/UsbKeyCodes.h
new file mode 100644
index 0000000..f0e4cbc
--- /dev/null
+++ b/emb/pastilda/keys/UsbKeyCodes.h
@@ -0,0 +1,354 @@
+/*
+ * This file is part of the pastilda project.
+ * hosted at http://github.com/thirdpin/pastilda
+ *
+ * Copyright (C) 2016 Third Pin LLC
+ *
+ * Written by:
+ * Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ * Dmitrii Lisin <mrlisdim@ya.ru>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef KEYS_USBKEYCODES_H_
+#define KEYS_USBKEYCODES_H_
+
+#include <cstddef>
+#include <cstdint>
+
+namespace Keys {
+
+typedef uint8_t UsbKeyCodeType;
+
+enum class UsbKey : UsbKeyCodeType {
+ NOT_A_KEY = 0x00,
+ KEY_ERRORROLLOVER = 0x01,
+ KEY_POSTFAIL = 0x02,
+ KEY_ERRORUNDEFINED = 0x03,
+ KEY_A = 0x04,
+ KEY_B = 0x05,
+ KEY_C = 0x06,
+ KEY_D = 0x07,
+ KEY_E = 0x08,
+ KEY_F = 0x09,
+ KEY_G = 0x0A,
+ KEY_H = 0x0B,
+ KEY_I = 0x0C,
+ KEY_J = 0x0D,
+ KEY_K = 0x0E,
+ KEY_L = 0x0F,
+ KEY_M = 0x10,
+ KEY_N = 0x11,
+ KEY_O = 0x12,
+ KEY_P = 0x13,
+ KEY_Q = 0x14,
+ KEY_R = 0x15,
+ KEY_S = 0x16,
+ KEY_T = 0x17,
+ KEY_U = 0x18,
+ KEY_V = 0x19,
+ KEY_W = 0x1A,
+ KEY_X = 0x1B,
+ KEY_Y = 0x1C,
+ KEY_Z = 0x1D,
+ KEY_1_EXCLAMATION_MARK = 0x1E,
+ KEY_2_AT = 0x1F,
+ KEY_3_NUMBER_SIGN = 0x20,
+ KEY_4_DOLLAR = 0x21,
+ KEY_5_PERCENT = 0x22,
+ KEY_6_CARET = 0x23,
+ KEY_7_AMPERSAND = 0x24,
+ KEY_8_ASTERISK = 0x25,
+ KEY_9_OPARENTHESIS = 0x26,
+ KEY_0_CPARENTHESIS = 0x27,
+ KEY_ENTER = 0x28,
+ KEY_ESCAPE = 0x29,
+ KEY_BACKSPACE = 0x2A,
+ KEY_TAB = 0x2B,
+ KEY_SPACEBAR = 0x2C,
+ KEY_MINUS_UNDERSCORE = 0x2D,
+ KEY_EQUAL_PLUS = 0x2E,
+ KEY_OBRACKET_AND_OBRACE = 0x2F,
+ KEY_CBRACKET_AND_CBRACE = 0x30,
+ KEY_BACKSLASH_VERTICAL_BAR = 0x31,
+ KEY_NONUS_NUMBER_SIGN_TILDE = 0x32,
+ KEY_SEMICOLON_COLON = 0x33,
+ KEY_SINGLE_AND_DOUBLE_QUOTE = 0x34,
+ KEY_GRAVE_ACCENT_AND_TILDE = 0x35,
+ KEY_COMMA_AND_LESS = 0x36,
+ KEY_DOT_GREATER = 0x37,
+ KEY_SLASH_QUESTION = 0x38,
+ KEY_CAPS_LOCK = 0x39,
+ KEY_F1 = 0x3A,
+ KEY_F2 = 0x3B,
+ KEY_F3 = 0x3C,
+ KEY_F4 = 0x3D,
+ KEY_F5 = 0x3E,
+ KEY_F6 = 0x3F,
+ KEY_F7 = 0x40,
+ KEY_F8 = 0x41,
+ KEY_F9 = 0x42,
+ KEY_F10 = 0x43,
+ KEY_F11 = 0x44,
+ KEY_F12 = 0x45,
+ KEY_PRINTSCREEN = 0x46,
+ KEY_SCROLL_LOCK = 0x47,
+ KEY_PAUSE = 0x48,
+ KEY_INSERT = 0x49,
+ KEY_HOME = 0x4A,
+ KEY_PAGEUP = 0x4B,
+ KEY_DELETE = 0x4C,
+ KEY_END1 = 0x4D,
+ KEY_PAGEDOWN = 0x4E,
+ KEY_RIGHTARROW = 0x4F,
+ KEY_LEFTARROW = 0x50,
+ KEY_DOWNARROW = 0x51,
+ KEY_UPARROW = 0x52,
+ KEY_KEYPAD_NUM_LOCK_AND_CLEAR = 0x53,
+ KEY_KEYPAD_SLASH = 0x54,
+ KEY_KEYPAD_ASTERIKS = 0x55,
+ KEY_KEYPAD_MINUS = 0x56,
+ KEY_KEYPAD_PLUS = 0x57,
+ KEY_KEYPAD_ENTER = 0x58,
+ KEY_KEYPAD_1_END = 0x59,
+ KEY_KEYPAD_2_DOWN_ARROW = 0x5A,
+ KEY_KEYPAD_3_PAGEDN = 0x5B,
+ KEY_KEYPAD_4_LEFT_ARROW = 0x5C,
+ KEY_KEYPAD_5 = 0x5D,
+ KEY_KEYPAD_6_RIGHT_ARROW = 0x5E,
+ KEY_KEYPAD_7_HOME = 0x5F,
+ KEY_KEYPAD_8_UP_ARROW = 0x60,
+ KEY_KEYPAD_9_PAGEUP = 0x61,
+ KEY_KEYPAD_0_INSERT = 0x62,
+ KEY_KEYPAD_DECIMAL_SEPARATOR_DELETE = 0x63,
+ KEY_NONUS_BACK_SLASH_VERTICAL_BAR = 0x64,
+ KEY_APPLICATION = 0x65,
+ KEY_POWER = 0x66,
+ KEY_KEYPAD_EQUAL = 0x67,
+ KEY_F13 = 0x68,
+ KEY_F14 = 0x69,
+ KEY_F15 = 0x6A,
+ KEY_F16 = 0x6B,
+ KEY_F17 = 0x6C,
+ KEY_F18 = 0x6D,
+ KEY_F19 = 0x6E,
+ KEY_F20 = 0x6F,
+ KEY_F21 = 0x70,
+ KEY_F22 = 0x71,
+ KEY_F23 = 0x72,
+ KEY_F24 = 0x73,
+ KEY_EXECUTE = 0x74,
+ KEY_HELP = 0x75,
+ KEY_MENU = 0x76,
+ KEY_SELECT = 0x77,
+ KEY_STOP = 0x78,
+ KEY_AGAIN = 0x79,
+ KEY_UNDO = 0x7A,
+ KEY_CUT = 0x7B,
+ KEY_COPY = 0x7C,
+ KEY_PASTE = 0x7D,
+ KEY_FIND = 0x7E,
+ KEY_MUTE = 0x7F,
+ KEY_VOLUME_UP = 0x80,
+ KEY_VOLUME_DOWN = 0x81,
+ KEY_LOCKING_CAPS_LOCK = 0x82,
+ KEY_LOCKING_NUM_LOCK = 0x83,
+ KEY_LOCKING_SCROLL_LOCK = 0x84,
+ KEY_KEYPAD_COMMA = 0x85,
+ KEY_KEYPAD_EQUAL_SIGN = 0x86,
+ KEY_INTERNATIONAL1 = 0x87,
+ KEY_INTERNATIONAL2 = 0x88,
+ KEY_INTERNATIONAL3 = 0x89,
+ KEY_INTERNATIONAL4 = 0x8A,
+ KEY_INTERNATIONAL5 = 0x8B,
+ KEY_INTERNATIONAL6 = 0x8C,
+ KEY_INTERNATIONAL7 = 0x8D,
+ KEY_INTERNATIONAL8 = 0x8E,
+ KEY_INTERNATIONAL9 = 0x8F,
+ KEY_LANG1 = 0x90,
+ KEY_LANG2 = 0x91,
+ KEY_LANG3 = 0x92,
+ KEY_LANG4 = 0x93,
+ KEY_LANG5 = 0x94,
+ KEY_LANG6 = 0x95,
+ KEY_LANG7 = 0x96,
+ KEY_LANG8 = 0x97,
+ KEY_LANG9 = 0x98,
+ KEY_ALTERNATE_ERASE = 0x99,
+ KEY_SYSREQ = 0x9A,
+ KEY_CANCEL = 0x9B,
+ KEY_CLEAR = 0x9C,
+ KEY_PRIOR = 0x9D,
+ KEY_RETURN = 0x9E,
+ KEY_SEPARATOR = 0x9F,
+ KEY_OUT = 0xA0,
+ KEY_OPER = 0xA1,
+ KEY_CLEAR_AGAIN = 0xA2,
+ KEY_CRSEL = 0xA3,
+ KEY_EXSEL = 0xA4,
+ KEY_KEYPAD_00 = 0xB0,
+ KEY_KEYPAD_000 = 0xB1,
+ KEY_THOUSANDS_SEPARATOR = 0xB2,
+ KEY_DECIMAL_SEPARATOR = 0xB3,
+ KEY_CURRENCY_UNIT = 0xB4,
+ KEY_CURRENCY_SUB_UNIT = 0xB5,
+ KEY_KEYPAD_OPARENTHESIS = 0xB6,
+ KEY_KEYPAD_CPARENTHESIS = 0xB7,
+ KEY_KEYPAD_OBRACE = 0xB8,
+ KEY_KEYPAD_CBRACE = 0xB9,
+ KEY_KEYPAD_TAB = 0xBA,
+ KEY_KEYPAD_BACKSPACE = 0xBB,
+ KEY_KEYPAD_A = 0xBC,
+ KEY_KEYPAD_B = 0xBD,
+ KEY_KEYPAD_C = 0xBE,
+ KEY_KEYPAD_D = 0xBF,
+ KEY_KEYPAD_E = 0xC0,
+ KEY_KEYPAD_F = 0xC1,
+ KEY_KEYPAD_XOR = 0xC2,
+ KEY_KEYPAD_CARET = 0xC3,
+ KEY_KEYPAD_PERCENT = 0xC4,
+ KEY_KEYPAD_LESS = 0xC5,
+ KEY_KEYPAD_GREATER = 0xC6,
+ KEY_KEYPAD_AMPERSAND = 0xC7,
+ KEY_KEYPAD_LOGICAL_AND = 0xC8,
+ KEY_KEYPAD_VERTICAL_BAR = 0xC9,
+ KEY_KEYPAD_LOGICAL_OR = 0xCA,
+ KEY_KEYPAD_COLON = 0xCB,
+ KEY_KEYPAD_NUMBER_SIGN = 0xCC,
+ KEY_KEYPAD_SPACE = 0xCD,
+ KEY_KEYPAD_AT = 0xCE,
+ KEY_KEYPAD_EXCLAMATION_MARK = 0xCF,
+ KEY_KEYPAD_MEMORY_STORE = 0xD0,
+ KEY_KEYPAD_MEMORY_RECALL = 0xD1,
+ KEY_KEYPAD_MEMORY_CLEAR = 0xD2,
+ KEY_KEYPAD_MEMORY_ADD = 0xD3,
+ KEY_KEYPAD_MEMORY_SUBTRACT = 0xD4,
+ KEY_KEYPAD_MEMORY_MULTIPLY = 0xD5,
+ KEY_KEYPAD_MEMORY_DIVIDE = 0xD6,
+ KEY_KEYPAD_PLUSMINUS = 0xD7,
+ KEY_KEYPAD_CLEAR = 0xD8,
+ KEY_KEYPAD_CLEAR_ENTRY = 0xD9,
+ KEY_KEYPAD_BINARY = 0xDA,
+ KEY_KEYPAD_OCTAL = 0xDB,
+ KEY_KEYPAD_DECIMAL = 0xDC,
+ KEY_KEYPAD_HEXADECIMAL = 0xDD,
+ KEY_LEFTCONTROL = 0xE0,
+ KEY_LEFTSHIFT = 0xE1,
+ KEY_LEFTALT = 0xE2,
+ KEY_LEFT_GUI = 0xE3,
+ KEY_RIGHTCONTROL = 0xE4,
+ KEY_RIGHTSHIFT = 0xE5,
+ KEY_RIGHTALT = 0xE6,
+ KEY_RIGHT_GUI = 0xE7
+};
+
+static constexpr std::size_t USB_SPECIAL_KEY_CODE_COUNT = 8;
+enum class UsbSpecialKey : UsbKeyCodeType {
+ NO_KEY = 0x00,
+ LEFT_CTRL = 0x01,
+ LEFT_SHIFT = 0x02,
+ LEFT_ALT = 0x04,
+ LEFT_GUI = 0x08,
+ RIGHT_CTRL = 0x10,
+ RIGHT_SHIFT = 0x20,
+ RIGHT_ALT = 0x40,
+ RIGHT_GUI = 0x80
+};
+
+#pragma pack(push, 1)
+struct UsbSpecialKeySequence
+{
+ UsbKeyCodeType
+ leftCtrl : 1, // 00000001
+ leftShift : 1, // 00000010
+ leftAlt : 1, // 00000100
+ leftGui : 1, // 00001000
+ rightCtrl : 1, // 00010000
+ rightShift : 1, // 00100000
+ rightAlt : 1, // 01000000
+ rightGui : 1; // 10000000
+
+ const UsbKeyCodeType getMask() const {
+ return *reinterpret_cast<const UsbKeyCodeType*>(this);
+ }
+
+ void set(UsbKeyCodeType mask) {
+ *reinterpret_cast<UsbKeyCodeType*>(this) = mask;
+ }
+
+ void clear() {
+ set(0);
+ }
+
+ void set(UsbKeyCodeType key1,
+ UsbKeyCodeType key2,
+ UsbKeyCodeType key3 = 0,
+ UsbKeyCodeType key4 = 0,
+ UsbKeyCodeType key5 = 0,
+ UsbKeyCodeType key6 = 0,
+ UsbKeyCodeType key7 = 0,
+ UsbKeyCodeType key8 = 0)
+ {
+ set(key1 | key2 | key3 | key4 | key5 | key6 | key7 | key8);
+ }
+
+ void set(UsbSpecialKey key1,
+ UsbSpecialKey key2 = UsbSpecialKey::NO_KEY,
+ UsbSpecialKey key3 = UsbSpecialKey::NO_KEY,
+ UsbSpecialKey key4 = UsbSpecialKey::NO_KEY,
+ UsbSpecialKey key5 = UsbSpecialKey::NO_KEY,
+ UsbSpecialKey key6 = UsbSpecialKey::NO_KEY,
+ UsbSpecialKey key7 = UsbSpecialKey::NO_KEY,
+ UsbSpecialKey key8 = UsbSpecialKey::NO_KEY)
+ {
+ set(
+ static_cast<UsbKeyCodeType>(key1) |
+ static_cast<UsbKeyCodeType>(key2) |
+ static_cast<UsbKeyCodeType>(key3) |
+ static_cast<UsbKeyCodeType>(key4) |
+ static_cast<UsbKeyCodeType>(key5) |
+ static_cast<UsbKeyCodeType>(key6) |
+ static_cast<UsbKeyCodeType>(key7) |
+ static_cast<UsbKeyCodeType>(key8)
+ );
+ }
+
+ void set(UsbSpecialKeySequence& seq) {
+ set(seq.getMask());
+ }
+
+ bool isSetted(UsbSpecialKey key) {
+ return ((static_cast<UsbKeyCodeType>(key) & getMask()) != 0);
+ }
+
+ template<typename T>
+ UsbSpecialKeySequence& operator=(const T& src) {
+ set(src);
+ return *this;
+ }
+
+ bool operator==(UsbSpecialKey key) const {
+ return (static_cast<UsbKeyCodeType>(key) == getMask());
+ }
+
+ bool operator==(UsbSpecialKeySequence seq) const {
+ return (seq.getMask() == getMask());
+ }
+};
+#pragma pack(pop)
+
+}
+
+#endif /* KEYS_USBKEYCODES_H_ */
diff --git a/emb/pastilda/app/leds.cpp b/emb/pastilda/leds/leds.cpp
index 92907cf..c7d5a97 100644
--- a/emb/pastilda/app/leds.cpp
+++ b/emb/pastilda/leds/leds.cpp
@@ -3,7 +3,10 @@
* hosted at http://github.com/thirdpin/pastilda
*
* Copyright (C) 2016 Third Pin LLC
- * Written by Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ *
+ * Written by:
+ * Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ * Dmitrii Lisin <mrlisdim@ya.ru>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,21 +27,21 @@
using namespace LEDS_API;
LEDS_api::LEDS_api()
+: _timer_leds_toggle(TimerMode::CYCLE, LEDS_TOGGLE_PERIOD_MS), _leds_state(LEDS_INI_STATE)
{
- _leds[0] = new GPIO_ext(LED_R);
- _leds[1] = new GPIO_ext(LED_G);
- _leds[2] = new GPIO_ext(LED_B);
- _leds[0]->mode_setup(Mode::OUTPUT, PullMode::NO_PULL);
- _leds[1]->mode_setup(Mode::OUTPUT, PullMode::NO_PULL);
- _leds[2]->mode_setup(Mode::OUTPUT, PullMode::NO_PULL);
+ _leds[0].init(LED_R);
+ _leds[1].init(LED_G);
+ _leds[2].init(LED_B);
+ _leds[0].mode_setup(Mode::OUTPUT, PullMode::NO_PULL);
+ _leds[1].mode_setup(Mode::OUTPUT, PullMode::NO_PULL);
+ _leds[2].mode_setup(Mode::OUTPUT, PullMode::NO_PULL);
_leds_state = LEDS_INI_STATE;
- _timer_leds_toggle = new TimerMs(TimerMode::CYCLE, LEDS_TOGGLE_PERIOD_MS);
}
void LEDS_api::toggle()
{
- if (_timer_leds_toggle->timeout()) {
+ if (_timer_leds_toggle.timeout()) {
leds_toggle();
}
}
@@ -48,10 +51,10 @@ void LEDS_api::leds_toggle()
uint8_t mask = LEDS_INI_STATE;
for(int i = 0; i < LEDS_COUNT; i++) {
if (!(_leds_state & mask)) {
- _leds[i]->set();
+ _leds[i].set();
}
else {
- _leds[i]->clear();
+ _leds[i].clear();
}
mask = mask << 1;
diff --git a/emb/pastilda/app/leds.h b/emb/pastilda/leds/leds.h
index 1bd3c74..4e0ff77 100644
--- a/emb/pastilda/app/leds.h
+++ b/emb/pastilda/leds/leds.h
@@ -3,7 +3,10 @@
* hosted at http://github.com/thirdpin/pastilda
*
* Copyright (C) 2016 Third Pin LLC
- * Written by Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ *
+ * Written by:
+ * Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ * Dmitrii Lisin <mrlisdim@ya.ru>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -35,7 +38,7 @@ namespace LEDS_API
constexpr uint8_t LEDS_COUNT = 0x03;
constexpr uint8_t LEDS_MAX_STATE = 0x07;
constexpr uint8_t LEDS_INI_STATE = 0x01;
- constexpr uint32_t LEDS_TOGGLE_PERIOD_MS = 500;
+ constexpr uint32_t LEDS_TOGGLE_PERIOD_MS = 1000;
class LEDS_api
{
@@ -44,9 +47,8 @@ namespace LEDS_API
void toggle();
private:
- TimerMs *_timer_leds_toggle;
- GPIO_ext *_leds[LEDS_COUNT];
-
+ TimerMs _timer_leds_toggle;
+ GPIO_ext _leds[LEDS_COUNT];
uint8_t _leds_state;
void leds_toggle();
diff --git a/emb/pastilda/lib/crypto/base64.h b/emb/pastilda/lib/crypto/base64.h
new file mode 100644
index 0000000..3ffaf77
--- /dev/null
+++ b/emb/pastilda/lib/crypto/base64.h
@@ -0,0 +1,255 @@
+#ifndef BASE64_H
+#define BASE64_H
+
+#include <string>
+
+const char kBase64Alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+class Base64 {
+ public:
+ static bool Encode(const std::string &in, std::string *out) {
+ int i = 0, j = 0;
+ size_t enc_len = 0;
+ unsigned char a3[3];
+ unsigned char a4[4];
+
+ out->resize(EncodedLength(in));
+
+ int input_len = in.size();
+ std::string::const_iterator input = in.begin();
+
+ while (input_len--) {
+ a3[i++] = *(input++);
+ if (i == 3) {
+ a3_to_a4(a4, a3);
+
+ for (i = 0; i < 4; i++) {
+ (*out)[enc_len++] = kBase64Alphabet[a4[i]];
+ }
+
+ i = 0;
+ }
+ }
+
+ if (i) {
+ for (j = i; j < 3; j++) {
+ a3[j] = '\0';
+ }
+
+ a3_to_a4(a4, a3);
+
+ for (j = 0; j < i + 1; j++) {
+ (*out)[enc_len++] = kBase64Alphabet[a4[j]];
+ }
+
+ while ((i++ < 3)) {
+ (*out)[enc_len++] = '=';
+ }
+ }
+
+ return (enc_len == out->size());
+ }
+
+ static bool Encode(const char *input, size_t input_length, char *out, size_t out_length) {
+ int i = 0, j = 0;
+ char *out_begin = out;
+ unsigned char a3[3];
+ unsigned char a4[4];
+
+ size_t encoded_length = EncodedLength(input_length);
+
+ if (out_length < encoded_length) return false;
+
+ while (input_length--) {
+ a3[i++] = *input++;
+ if (i == 3) {
+ a3_to_a4(a4, a3);
+
+ for (i = 0; i < 4; i++) {
+ *out++ = kBase64Alphabet[a4[i]];
+ }
+
+ i = 0;
+ }
+ }
+
+ if (i) {
+ for (j = i; j < 3; j++) {
+ a3[j] = '\0';
+ }
+
+ a3_to_a4(a4, a3);
+
+ for (j = 0; j < i + 1; j++) {
+ *out++ = kBase64Alphabet[a4[j]];
+ }
+
+ while ((i++ < 3)) {
+ *out++ = '=';
+ }
+ }
+
+ return (out == (out_begin + encoded_length));
+ }
+
+ static bool Decode(const std::string &in, std::string *out) {
+ int i = 0, j = 0;
+ size_t dec_len = 0;
+ unsigned char a3[3];
+ unsigned char a4[4];
+
+ int input_len = in.size();
+ std::string::const_iterator input = in.begin();
+
+ out->resize(DecodedLength(in));
+
+ while (input_len--) {
+ if (*input == '=') {
+ break;
+ }
+
+ a4[i++] = *(input++);
+ if (i == 4) {
+ for (i = 0; i <4; i++) {
+ a4[i] = b64_lookup(a4[i]);
+ }
+
+ a4_to_a3(a3,a4);
+
+ for (i = 0; i < 3; i++) {
+ (*out)[dec_len++] = a3[i];
+ }
+
+ i = 0;
+ }
+ }
+
+ if (i) {
+ for (j = i; j < 4; j++) {
+ a4[j] = '\0';
+ }
+
+ for (j = 0; j < 4; j++) {
+ a4[j] = b64_lookup(a4[j]);
+ }
+
+ a4_to_a3(a3,a4);
+
+ for (j = 0; j < i - 1; j++) {
+ (*out)[dec_len++] = a3[j];
+ }
+ }
+
+ return (dec_len == out->size());
+ }
+
+ static bool Decode(const char *input, size_t input_length, char *out, size_t out_length, uint32_t *res_length) {
+ int i = 0, j = 0;
+ char *out_begin = out;
+ unsigned char a3[3];
+ unsigned char a4[4];
+
+ size_t decoded_length = DecodedLength(input, input_length);
+ *res_length = decoded_length;
+
+ if (out_length < decoded_length) return false;
+
+ while (input_length--) {
+ if (*input == '=') {
+ break;
+ }
+
+ a4[i++] = *(input++);
+ if (i == 4) {
+ for (i = 0; i <4; i++) {
+ a4[i] = b64_lookup(a4[i]);
+ }
+
+ a4_to_a3(a3,a4);
+
+ for (i = 0; i < 3; i++) {
+ *out++ = a3[i];
+ }
+
+ i = 0;
+ }
+ }
+
+ if (i) {
+ for (j = i; j < 4; j++) {
+ a4[j] = '\0';
+ }
+
+ for (j = 0; j < 4; j++) {
+ a4[j] = b64_lookup(a4[j]);
+ }
+
+ a4_to_a3(a3,a4);
+
+ for (j = 0; j < i - 1; j++) {
+ *out++ = a3[j];
+ }
+ }
+
+ return (out == (out_begin + decoded_length));
+ }
+
+ static int DecodedLength(const char *in, size_t in_length) {
+ int numEq = 0;
+
+ const char *in_end = in + in_length;
+ while (*--in_end == '=') ++numEq;
+
+ return ((6 * in_length) / 8) - numEq;
+ }
+
+ static int DecodedLength(const std::string &in) {
+ int numEq = 0;
+ int n = in.size();
+
+ for (std::string::const_reverse_iterator it = in.rbegin(); *it == '='; ++it) {
+ ++numEq;
+ }
+
+ return ((6 * n) / 8) - numEq;
+ }
+
+ inline static int EncodedLength(size_t length) {
+ return (length + 2 - ((length + 2) % 3)) / 3 * 4;
+ }
+
+ inline static int EncodedLength(const std::string &in) {
+ return EncodedLength(in.length());
+ }
+
+ inline static void StripPadding(std::string *in) {
+ while (!in->empty() && *(in->rbegin()) == '=') in->resize(in->size() - 1);
+ }
+
+ private:
+ static inline void a3_to_a4(unsigned char * a4, unsigned char * a3) {
+ a4[0] = (a3[0] & 0xfc) >> 2;
+ a4[1] = ((a3[0] & 0x03) << 4) + ((a3[1] & 0xf0) >> 4);
+ a4[2] = ((a3[1] & 0x0f) << 2) + ((a3[2] & 0xc0) >> 6);
+ a4[3] = (a3[2] & 0x3f);
+ }
+
+ static inline void a4_to_a3(unsigned char * a3, unsigned char * a4) {
+ a3[0] = (a4[0] << 2) + ((a4[1] & 0x30) >> 4);
+ a3[1] = ((a4[1] & 0xf) << 4) + ((a4[2] & 0x3c) >> 2);
+ a3[2] = ((a4[2] & 0x3) << 6) + a4[3];
+ }
+
+ static inline unsigned char b64_lookup(unsigned char c) {
+ if(c >='A' && c <='Z') return c - 'A';
+ if(c >='a' && c <='z') return c - 71;
+ if(c >='0' && c <='9') return c + 4;
+ if(c == '+') return 62;
+ if(c == '/') return 63;
+ return 255;
+ }
+};
+
+
+
+#endif // BASE64_H
diff --git a/emb/pastilda/lib/crypto/bitops.h b/emb/pastilda/lib/crypto/bitops.h
new file mode 100644
index 0000000..d0e6942
--- /dev/null
+++ b/emb/pastilda/lib/crypto/bitops.h
@@ -0,0 +1,294 @@
+/*
+ * cifra - embedded cryptography library
+ * Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
+ *
+ * To the extent possible under law, the author(s) have dedicated all
+ * copyright and related and neighboring rights to this software to the
+ * public domain worldwide. This software is distributed without any
+ * warranty.
+ *
+ * You should have received a copy of the CC0 Public Domain Dedication
+ * along with this software. If not, see
+ * <http://creativecommons.org/publicdomain/zero/1.0/>.
+ */
+
+#ifndef BITOPS_H
+#define BITOPS_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+/* Assorted bitwise and common operations used in ciphers. */
+
+/** Circularly rotate right x by n bits.
+ * 0 > n > 32. */
+static inline uint32_t rotr32(uint32_t x, unsigned n)
+{
+ return (x >> n) | (x << (32 - n));
+}
+
+/** Circularly rotate left x by n bits.
+ * 0 > n > 32. */
+static inline uint32_t rotl32(uint32_t x, unsigned n)
+{
+ return (x << n) | (x >> (32 - n));
+}
+
+/** Circularly rotate right x by n bits.
+ * 0 > n > 64. */
+static inline uint64_t rotr64(uint64_t x, unsigned n)
+{
+ return (x >> n) | (x << (64 - n));
+}
+
+/** Circularly rotate left x by n bits.
+ * 0 > n > 64. */
+static inline uint64_t rotl64(uint64_t x, unsigned n)
+{
+ return (x << n) | (x >> (64 - n));
+}
+
+/** Read 4 bytes from buf, as a 32-bit big endian quantity. */
+static inline uint32_t read32_be(const uint8_t buf[4])
+{
+ return (buf[0] << 24) |
+ (buf[1] << 16) |
+ (buf[2] << 8) |
+ (buf[3]);
+}
+
+/** Read 4 bytes from buf, as a 32-bit little endian quantity. */
+static inline uint32_t read32_le(const uint8_t buf[4])
+{
+ return (buf[3] << 24) |
+ (buf[2] << 16) |
+ (buf[1] << 8) |
+ (buf[0]);
+}
+
+/** Read 8 bytes from buf, as a 64-bit big endian quantity. */
+static inline uint64_t read64_be(const uint8_t buf[8])
+{
+ uint32_t hi = read32_be(buf),
+ lo = read32_be(buf + 4);
+ return ((uint64_t)hi) << 32 |
+ lo;
+}
+
+/** Read 8 bytes from buf, as a 64-bit little endian quantity. */
+static inline uint64_t read64_le(const uint8_t buf[8])
+{
+ uint32_t hi = read32_le(buf + 4),
+ lo = read32_le(buf);
+ return ((uint64_t)hi) << 32 |
+ lo;
+}
+
+/** Encode v as a 32-bit big endian quantity into buf. */
+static inline void write32_be(uint32_t v, uint8_t buf[4])
+{
+ *buf++ = (v >> 24) & 0xff;
+ *buf++ = (v >> 16) & 0xff;
+ *buf++ = (v >> 8) & 0xff;
+ *buf = v & 0xff;
+}
+
+/** Encode v as a 32-bit little endian quantity into buf. */
+static inline void write32_le(uint32_t v, uint8_t buf[4])
+{
+ *buf++ = v & 0xff;
+ *buf++ = (v >> 8) & 0xff;
+ *buf++ = (v >> 16) & 0xff;
+ *buf = (v >> 24) & 0xff;
+}
+
+/** Encode v as a 64-bit big endian quantity into buf. */
+static inline void write64_be(uint64_t v, uint8_t buf[8])
+{
+ *buf++ = (v >> 56) & 0xff;
+ *buf++ = (v >> 48) & 0xff;
+ *buf++ = (v >> 40) & 0xff;
+ *buf++ = (v >> 32) & 0xff;
+ *buf++ = (v >> 24) & 0xff;
+ *buf++ = (v >> 16) & 0xff;
+ *buf++ = (v >> 8) & 0xff;
+ *buf = v & 0xff;
+}
+
+/** Encode v as a 64-bit little endian quantity into buf. */
+static inline void write64_le(uint64_t v, uint8_t buf[8])
+{
+ *buf++ = v & 0xff;
+ *buf++ = (v >> 8) & 0xff;
+ *buf++ = (v >> 16) & 0xff;
+ *buf++ = (v >> 24) & 0xff;
+ *buf++ = (v >> 32) & 0xff;
+ *buf++ = (v >> 40) & 0xff;
+ *buf++ = (v >> 48) & 0xff;
+ *buf = (v >> 56) & 0xff;
+}
+
+/** out = in ^ b8.
+ * out and in may alias. */
+static inline void xor_b8(uint8_t *out, const uint8_t *in, uint8_t b8, size_t len)
+{
+ for (size_t i = 0; i < len; i++)
+ out[i] = in[i] ^ b8;
+}
+
+/** out = x ^ y.
+ * out, x and y may alias. */
+static inline void xor_bb(uint8_t *out, const uint8_t *x, const uint8_t *y, size_t len)
+{
+ for (size_t i = 0; i < len; i++)
+ out[i] = x[i] ^ y[i];
+}
+
+/* out ^= x
+ * out and x may alias. */
+static inline void xor_words(uint32_t *out, const uint32_t *x, size_t nwords)
+{
+ for (size_t i = 0; i < nwords; i++)
+ out[i] ^= x[i];
+}
+
+/** Produce 0xffffffff if x == y, zero otherwise, without branching. */
+static inline uint32_t mask_u32(uint32_t x, uint32_t y)
+{
+ uint32_t diff = x ^ y;
+ uint32_t diff_is_zero = ~diff & (diff - 1);
+ return - (diff_is_zero >> 31);
+}
+
+/** Product 0xff if x == y, zero otherwise, without branching. */
+static inline uint8_t mask_u8(uint32_t x, uint32_t y)
+{
+ uint32_t diff = x ^ y;
+ uint8_t diff_is_zero = ~diff & (diff - 1);
+ return - (diff_is_zero >> 7);
+}
+
+/** Select the ith entry from the given table of n values, in a side channel-silent
+ * way. */
+static inline uint32_t select_u32(uint32_t i, volatile const uint32_t *tab, uint32_t n)
+{
+ uint32_t r = 0;
+
+ for (uint32_t ii = 0; ii < n; ii++)
+ {
+ uint32_t mask = mask_u32(i, ii);
+ r = (r & ~mask) | (tab[ii] & mask);
+ }
+
+ return r;
+}
+
+/** Select the ith entry from the given table of n values, in a side channel-silent
+ * way. */
+static inline uint8_t select_u8(uint32_t i, volatile const uint8_t *tab, uint32_t n)
+{
+ uint8_t r = 0;
+
+ for (uint32_t ii = 0; ii < n; ii++)
+ {
+ uint8_t mask = mask_u8(i, ii);
+ r = (r & ~mask) | (tab[ii] & mask);
+ }
+
+ return r;
+}
+
+/** Select the ath, bth, cth and dth entries from the given table of n values,
+ * placing the results into a, b, c and d. */
+static inline void select_u8x4(uint8_t *a, uint8_t *b, uint8_t *c, uint8_t *d,
+ volatile const uint8_t *tab, uint32_t n)
+{
+ uint8_t ra = 0,
+ rb = 0,
+ rc = 0,
+ rd = 0;
+ uint8_t mask;
+
+ for (uint32_t i = 0; i < n; i++)
+ {
+ uint8_t item = tab[i];
+
+ mask = mask_u8(*a, i); ra = (ra & ~mask) | (item & mask);
+ mask = mask_u8(*b, i); rb = (rb & ~mask) | (item & mask);
+ mask = mask_u8(*c, i); rc = (rc & ~mask) | (item & mask);
+ mask = mask_u8(*d, i); rd = (rd & ~mask) | (item & mask);
+ }
+
+ *a = ra;
+ *b = rb;
+ *c = rc;
+ *d = rd;
+}
+
+/** out ^= if0 or if1, depending on the value of bit. */
+static inline void select_xor128(uint32_t out[4],
+ const uint32_t if0[4],
+ const uint32_t if1[4],
+ uint8_t bit)
+{
+ uint32_t mask1 = mask_u32(bit, 1);
+ uint32_t mask0 = ~mask1;
+
+ out[0] ^= (if0[0] & mask0) | (if1[0] & mask1);
+ out[1] ^= (if0[1] & mask0) | (if1[1] & mask1);
+ out[2] ^= (if0[2] & mask0) | (if1[2] & mask1);
+ out[3] ^= (if0[3] & mask0) | (if1[3] & mask1);
+}
+
+/** Increments the integer stored at v (of non-zero length len)
+ * with the least significant byte first. */
+static inline void incr_le(uint8_t *v, size_t len)
+{
+ size_t i = 0;
+ while (1)
+ {
+ if (++v[i] != 0)
+ return;
+ i++;
+ if (i == len)
+ return;
+ }
+}
+
+/** Increments the integer stored at v (of non-zero length len)
+ * with the most significant byte last. */
+static inline void incr_be(uint8_t *v, size_t len)
+{
+ len--;
+ while (1)
+ {
+ if (++v[len] != 0)
+ return;
+ if (len == 0)
+ return;
+ len--;
+ }
+}
+
+/** Copies len bytes from in to out, with in shifted left by offset bits
+ * to the right. */
+static inline void copy_bytes_unaligned(uint8_t *out, const uint8_t *in, size_t len, uint8_t offset)
+{
+ uint8_t byte_off = offset / 8;
+ uint8_t bit_off = offset & 7;
+ uint8_t rmask = (1 << bit_off) - 1;
+ uint8_t lmask = ~rmask;
+
+ for (size_t i = 0; i < len; i++)
+ {
+ out[i] = (in[i + byte_off] << bit_off) & lmask;
+ out[i] |= (in[i + byte_off + 1] >> (8 - bit_off)) & rmask;
+ }
+}
+
+static inline uint32_t count_trailing_zeroes(uint32_t x)
+{
+ return (uint32_t) __builtin_ctzl(x);
+}
+
+#endif
diff --git a/emb/pastilda/lib/crypto/blockwise.c b/emb/pastilda/lib/crypto/blockwise.c
new file mode 100644
index 0000000..74756e5
--- /dev/null
+++ b/emb/pastilda/lib/crypto/blockwise.c
@@ -0,0 +1,194 @@
+/*
+ * cifra - embedded cryptography library
+ * Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
+ *
+ * To the extent possible under law, the author(s) have dedicated all
+ * copyright and related and neighboring rights to this software to the
+ * public domain worldwide. This software is distributed without any
+ * warranty.
+ *
+ * You should have received a copy of the CC0 Public Domain Dedication
+ * along with this software. If not, see
+ * <http://creativecommons.org/publicdomain/zero/1.0/>.
+ */
+
+#include <bitops.h>
+#include <blockwise.h>
+#include <handy.h>
+#include <tassert.h>
+#include <string.h>
+
+void cf_blockwise_accumulate(uint8_t *partial, size_t *npartial, size_t nblock,
+ const void *inp, size_t nbytes,
+ cf_blockwise_in_fn process,
+ void *ctx)
+{
+ cf_blockwise_accumulate_final(partial, npartial, nblock,
+ inp, nbytes,
+ process, process, ctx);
+}
+
+void cf_blockwise_accumulate_final(uint8_t *partial, size_t *npartial, size_t nblock,
+ const void *inp, size_t nbytes,
+ cf_blockwise_in_fn process,
+ cf_blockwise_in_fn process_final,
+ void *ctx)
+{
+ const uint8_t *bufin = inp;
+ assert(partial && *npartial < nblock);
+ assert(inp || !nbytes);
+ assert(process && ctx);
+
+ /* If we have partial data, copy in to buffer. */
+ if (*npartial && nbytes)
+ {
+ size_t space = nblock - *npartial;
+ size_t taken = MIN(space, nbytes);
+
+ memcpy(partial + *npartial, bufin, taken);
+
+ bufin += taken;
+ nbytes -= taken;
+ *npartial += taken;
+
+ /* If that gives us a full block, process it. */
+ if (*npartial == nblock)
+ {
+ if (nbytes == 0)
+ process_final(ctx, partial);
+ else
+ process(ctx, partial);
+ *npartial = 0;
+ }
+ }
+
+ /* now nbytes < nblock or *npartial == 0. */
+
+ /* If we have a full block of data, process it directly. */
+ while (nbytes >= nblock)
+ {
+ /* Partial buffer must be empty, or we're ignoring extant data */
+ assert(*npartial == 0);
+
+ if (nbytes == nblock)
+ process_final(ctx, bufin);
+ else
+ process(ctx, bufin);
+ bufin += nblock;
+ nbytes -= nblock;
+ }
+
+ /* Finally, if we have remaining data, buffer it. */
+ while (nbytes)
+ {
+ size_t space = nblock - *npartial;
+ size_t taken = MIN(space, nbytes);
+
+ memcpy(partial + *npartial, bufin, taken);
+
+ bufin += taken;
+ nbytes -= taken;
+ *npartial += taken;
+
+ /* If we started with *npartial, we must have copied it
+ * in first. */
+ assert(*npartial < nblock);
+ }
+}
+
+void cf_blockwise_xor(uint8_t *partial, size_t *npartial, size_t nblock,
+ const void *inp, void *outp, size_t nbytes,
+ cf_blockwise_out_fn process, void *ctx)
+{
+ const uint8_t *inb = inp;
+ uint8_t *outb = outp;
+
+ assert(partial && *npartial < nblock);
+ assert(inp || !nbytes);
+ assert(process && ctx);
+
+ while (nbytes)
+ {
+ /* If we're out of material, and need more, produce a block. */
+ if (*npartial == 0)
+ {
+ process(ctx, partial);
+ *npartial = nblock;
+ }
+
+ size_t offset = nblock - *npartial;
+ size_t taken = MIN(*npartial, nbytes);
+ xor_bb(outb, inb, partial + offset, taken);
+ *npartial -= taken;
+ nbytes -= taken;
+ outb += taken;
+ inb += taken;
+ }
+}
+
+void cf_blockwise_acc_byte(uint8_t *partial, size_t *npartial,
+ size_t nblock,
+ uint8_t byte, size_t nbytes,
+ cf_blockwise_in_fn process,
+ void *ctx)
+{
+ /* only memset the whole of the block once */
+ int filled = 0;
+
+ while (nbytes)
+ {
+ size_t start = *npartial;
+ size_t count = MIN(nbytes, nblock - start);
+
+ if (!filled)
+ memset(partial + start, byte, count);
+
+ if (start == 0 && count == nblock)
+ filled = 1;
+
+ if (start + count == nblock)
+ {
+ process(ctx, partial);
+ *npartial = 0;
+ } else {
+ *npartial += count;
+ }
+
+ nbytes -= count;
+ }
+}
+
+void cf_blockwise_acc_pad(uint8_t *partial, size_t *npartial,
+ size_t nblock,
+ uint8_t fbyte, uint8_t mbyte, uint8_t lbyte,
+ size_t nbytes,
+ cf_blockwise_in_fn process,
+ void *ctx)
+{
+
+ switch (nbytes)
+ {
+ case 0: break;
+ case 1: fbyte ^= lbyte;
+ cf_blockwise_accumulate(partial, npartial, nblock, &fbyte, 1, process, ctx);
+ break;
+ case 2:
+ cf_blockwise_accumulate(partial, npartial, nblock, &fbyte, 1, process, ctx);
+ cf_blockwise_accumulate(partial, npartial, nblock, &lbyte, 1, process, ctx);
+ break;
+ default:
+ cf_blockwise_accumulate(partial, npartial, nblock, &fbyte, 1, process, ctx);
+
+ /* If the middle and last bytes differ, then process the last byte separately.
+ * Otherwise, just extend the middle block size. */
+ if (lbyte != mbyte)
+ {
+ cf_blockwise_acc_byte(partial, npartial, nblock, mbyte, nbytes - 2, process, ctx);
+ cf_blockwise_accumulate(partial, npartial, nblock, &lbyte, 1, process, ctx);
+ } else {
+ cf_blockwise_acc_byte(partial, npartial, nblock, mbyte, nbytes - 1, process, ctx);
+ }
+
+ break;
+ }
+}
diff --git a/emb/pastilda/lib/crypto/blockwise.h b/emb/pastilda/lib/crypto/blockwise.h
new file mode 100644
index 0000000..a20ff95
--- /dev/null
+++ b/emb/pastilda/lib/crypto/blockwise.h
@@ -0,0 +1,147 @@
+/*
+ * cifra - embedded cryptography library
+ * Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
+ *
+ * To the extent possible under law, the author(s) have dedicated all
+ * copyright and related and neighboring rights to this software to the
+ * public domain worldwide. This software is distributed without any
+ * warranty.
+ *
+ * You should have received a copy of the CC0 Public Domain Dedication
+ * along with this software. If not, see
+ * <http://creativecommons.org/publicdomain/zero/1.0/>.
+ */
+
+#ifndef BLOCKWISE_H
+#define BLOCKWISE_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+/* Processing function for cf_blockwise_accumulate. */
+typedef void (*cf_blockwise_in_fn)(void *ctx, const uint8_t *data);
+
+/* Processing function for cf_blockwise_xor. */
+typedef void (*cf_blockwise_out_fn)(void *ctx, uint8_t *data);
+
+/* This function manages the common abstraction of accumulating input in
+ * a buffer, and processing it when a full block is available.
+ *
+ * partial is the buffer (maintained by the caller)
+ * on entry, npartial is the currently valid count of used bytes on
+ * the front of partial.
+ * on exit, npartial is updated to reflect the status of partial.
+ * nblock is the blocksize to accumulate -- partial must be at least
+ * this long!
+ * input is the new data to process, of length nbytes.
+ * process is the processing function, passed ctx and a pointer
+ * to the data to process (always exactly nblock bytes long!)
+ * which may not neccessarily be the same as partial.
+ */
+void cf_blockwise_accumulate(uint8_t *partial, size_t *npartial,
+ size_t nblock,
+ const void *input, size_t nbytes,
+ cf_blockwise_in_fn process,
+ void *ctx);
+
+/* This function manages the common abstraction of accumulating input in
+ * a buffer, and processing it when a full block is available.
+ * This version supports calling a different processing function for
+ * the last block.
+ *
+ * partial is the buffer (maintained by the caller)
+ * on entry, npartial is the currently valid count of used bytes on
+ * the front of partial.
+ * on exit, npartial is updated to reflect the status of partial.
+ * nblock is the blocksize to accumulate -- partial must be at least
+ * this long!
+ * input is the new data to process, of length nbytes.
+ * process is the processing function, passed ctx and a pointer
+ * to the data to process (always exactly nblock bytes long!)
+ * which may not neccessarily be the same as partial.
+ * process_final is called last (but may not be called at all if
+ * all input is buffered).
+ */
+void cf_blockwise_accumulate_final(uint8_t *partial, size_t *npartial,
+ size_t nblock,
+ const void *input, size_t nbytes,
+ cf_blockwise_in_fn process,
+ cf_blockwise_in_fn process_final,
+ void *ctx);
+
+/* This function manages XORing an input stream with a keystream
+ * to produce an output stream. The keystream is produced in blocks
+ * (ala a block cipher in counter mode).
+ *
+ * partial is the keystream buffer (maintained by the caller)
+ * on entry, *npartial is the currently valid count of bytes in partial:
+ * unused bytes are at the *end*. So *npartial = 4 means the last four
+ * bytes of partial are usable as keystream.
+ * on exit, npartial is updated to reflect the new state of partial.
+ * nblock is the blocksize to accumulate -- partial must be at least
+ * this long!
+ * input is the new data to process, of length nbytes.
+ * output is where to write input xored with the keystream -- also length
+ * nbytes.
+ * process is the processing function, passed ctx and partial which it
+ * should fill with fresh key stream.
+ */
+void cf_blockwise_xor(uint8_t *partial, size_t *npartial,
+ size_t nblock,
+ const void *input, void *output, size_t nbytes,
+ cf_blockwise_out_fn newblock,
+ void *ctx);
+
+/* This function processes a single byte a number of times. It's useful
+ * for padding, and more efficient than calling cf_blockwise_accumulate
+ * a bunch of times.
+ *
+ * partial is the buffer (maintained by the caller)
+ * on entry, npartial is the currently valid count of used bytes on
+ * the front of partial.
+ * on exit, npartial is updated to reflect the status of partial.
+ * nblock is the blocksize to accumulate -- partial must be at least
+ * this long!
+ * process is the processing function, passed ctx and a pointer
+ * to the data to process (always exactly nblock bytes long!)
+ * which may not neccessarily be the same as partial.
+ * byte is the byte to process, nbytes times.
+ */
+void cf_blockwise_acc_byte(uint8_t *partial, size_t *npartial,
+ size_t nblock,
+ uint8_t byte, size_t nbytes,
+ cf_blockwise_in_fn process,
+ void *ctx);
+
+/* This function attempts to process patterns of bytes common in
+ * block cipher padding.
+ *
+ * This takes three bytes:
+ * - a first byte, fbyte,
+ * - a middle byte, mbyte,
+ * - a last byte, lbyte.
+ *
+ * If nbytes is zero, nothing happens.
+ * If nbytes is one, the byte fbyte ^ lbyte is processed.
+ * If nbytes is two, the fbyte then lbyte are processed.
+ * If nbytes is three or more, fbyte, then one or more mbytes, then fbyte
+ * is processed.
+ *
+ * partial is the buffer (maintained by the caller)
+ * on entry, npartial is the currently valid count of used bytes on
+ * the front of partial.
+ * on exit, npartial is updated to reflect the status of partial.
+ * nblock is the blocksize to accumulate -- partial must be at least
+ * this long!
+ * process is the processing function, passed ctx and a pointer
+ * to the data to process (always exactly nblock bytes long!)
+ * which may not neccessarily be the same as partial.
+ */
+void cf_blockwise_acc_pad(uint8_t *partial, size_t *npartial,
+ size_t nblock,
+ uint8_t fbyte, uint8_t mbyte, uint8_t lbyte,
+ size_t nbytes,
+ cf_blockwise_in_fn process,
+ void *ctx);
+
+#endif
diff --git a/emb/pastilda/lib/crypto/chash.c b/emb/pastilda/lib/crypto/chash.c
new file mode 100644
index 0000000..edd2e05
--- /dev/null
+++ b/emb/pastilda/lib/crypto/chash.c
@@ -0,0 +1,28 @@
+/*
+ * cifra - embedded cryptography library
+ * Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
+ *
+ * To the extent possible under law, the author(s) have dedicated all
+ * copyright and related and neighboring rights to this software to the
+ * public domain worldwide. This software is distributed without any
+ * warranty.
+ *
+ * You should have received a copy of the CC0 Public Domain Dedication
+ * along with this software. If not, see
+ * <http://creativecommons.org/publicdomain/zero/1.0/>.
+ */
+
+#include <chash.h>
+#include <handy.h>
+#include <tassert.h>
+
+void cf_hash(const cf_chash *h, const void *m, size_t nm, uint8_t *out)
+{
+ cf_chash_ctx ctx;
+ assert(h);
+ h->init(&ctx);
+ h->update(&ctx, m, nm);
+ h->digest(&ctx, out);
+ mem_clean(&ctx, sizeof ctx);
+}
+
diff --git a/emb/pastilda/lib/crypto/chash.h b/emb/pastilda/lib/crypto/chash.h
new file mode 100644
index 0000000..8f2e201
--- /dev/null
+++ b/emb/pastilda/lib/crypto/chash.h
@@ -0,0 +1,137 @@
+/*
+ * cifra - embedded cryptography library
+ * Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
+ *
+ * To the extent possible under law, the author(s) have dedicated all
+ * copyright and related and neighboring rights to this software to the
+ * public domain worldwide. This software is distributed without any
+ * warranty.
+ *
+ * You should have received a copy of the CC0 Public Domain Dedication
+ * along with this software. If not, see
+ * <http://creativecommons.org/publicdomain/zero/1.0/>.
+ */
+
+#ifndef CHASH_H
+#define CHASH_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+/**
+ * General hash function description
+ * =================================
+ * This allows us to make use of hash functions without depending
+ * on a specific one. This is useful in implementing, for example,
+ * :doc:`HMAC <hmac>`.
+ */
+
+/* .. c:type:: cf_chash_init
+ * Hashing initialisation function type.
+ *
+ * Functions of this type should initialise the context in preparation
+ * for hashing a message with `cf_chash_update` functions.
+ *
+ * :rtype: void
+ * :param ctx: hash function-specific context structure.
+ */
+typedef void (*cf_chash_init)(void *ctx);
+
+/* .. c:type:: cf_chash_update
+ * Hashing data processing function type.
+ *
+ * Functions of this type hash `count` bytes of data at `data`,
+ * updating the contents of `ctx`.
+ *
+ * :rtype: void
+ * :param ctx: hash function-specific context structure.
+ * :param data: input data to hash.
+ * :param count: number of bytes to hash.
+ */
+typedef void (*cf_chash_update)(void *ctx, const void *data, size_t count);
+
+/* .. c:type:: cf_chash_digest
+ * Hashing completion function type.
+ *
+ * Functions of this type complete a hashing operation,
+ * writing :c:member:`cf_chash.hashsz` bytes to `hash`.
+ *
+ * This function does not change `ctx` -- any padding which needs doing
+ * must be done seperately (in a copy of `ctx`, say).
+ *
+ * This means you can interlave `_update` and `_digest` calls to
+ * learn `H(A)` and `H(A || B)` without hashing `A` twice.
+ *
+ * :rtype: void
+ * :param ctx: hash function-specific context structure.
+ * :param hash: location to write hash result.
+ */
+typedef void (*cf_chash_digest)(const void *ctx, uint8_t *hash);
+
+/* .. c:type:: cf_chash
+ * This type describes an incremental hash function in an abstract way.
+ *
+ * .. c:member:: cf_chash.hashsz
+ * The hash function's output, in bytes.
+ *
+ * .. c:member:: cf_chash.blocksz
+ * The hash function's internal block size, in bytes.
+ *
+ * .. c:member:: cf_chash.init
+ * Context initialisation function.
+ *
+ * .. c:member:: cf_chash:update
+ * Data processing function.
+ *
+ * .. c:member:: cf_chash:digest
+ * Completion function.
+ *
+ */
+typedef struct
+{
+ size_t hashsz;
+ size_t blocksz;
+
+ cf_chash_init init;
+ cf_chash_update update;
+ cf_chash_digest digest;
+} cf_chash;
+
+/* .. c:macro:: CF_CHASH_MAXCTX
+ * The maximum size of a :c:type:`cf_chash_ctx`. This allows
+ * use to put a structure in automatic storage that can
+ * store working data for any supported hash function. */
+#define CF_CHASH_MAXCTX 360
+
+/* .. c:macro:: CF_CHASH_MAXBLK
+ * Maximum hash function block size (in bytes). */
+#define CF_CHASH_MAXBLK 128
+
+/* .. c:macro:: CF_MAXHASH
+ * Maximum hash function output (in bytes). */
+#define CF_MAXHASH 64
+
+/* .. c:type:: cf_chash_ctx
+ * A type usable with any `cf_chash` as a context. */
+typedef union
+{
+ uint8_t ctx[CF_CHASH_MAXCTX];
+ uint16_t u16;
+ uint32_t u32;
+ uint64_t u64;
+} cf_chash_ctx;
+
+/* .. c:function:: $DECL
+ * One shot hashing: `out = h(m)`.
+ *
+ * Using the hash function `h`, `nm` bytes at `m` are hashed and `h->hashsz` bytes
+ * of result is written to the buffer `out`.
+ *
+ * :param h: hash function description.
+ * :param m: message buffer.
+ * :param nm: message length.
+ * :param out: hash result buffer (written).
+ */
+void cf_hash(const cf_chash *h, const void *m, size_t nm, uint8_t *out);
+
+#endif
diff --git a/emb/pastilda/lib/crypto/handy.h b/emb/pastilda/lib/crypto/handy.h
new file mode 100644
index 0000000..a9b2d9d
--- /dev/null
+++ b/emb/pastilda/lib/crypto/handy.h
@@ -0,0 +1,86 @@
+#ifndef HANDY_H
+#define HANDY_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+/*
+ * Handy CPP defines and C inline functions.
+ */
+
+/* Evaluates to the number of items in array-type variable arr. */
+#define ARRAYCOUNT(arr) (sizeof arr / sizeof arr[0])
+
+/* Normal MIN/MAX macros. Evaluate argument expressions only once. */
+#ifndef MIN
+ #define MIN(x, y) \
+ ({ typeof (x) __x = (x); \
+ typeof (y) __y = (y); \
+ __x < __y ? __x : __y; })
+#endif
+#ifndef MAX
+ #define MAX(x, y) \
+ ({ typeof (x) __x = (x); \
+ typeof (y) __y = (y); \
+ __x > __y ? __x : __y; })
+#endif
+
+/* Swap two values. Uses GCC type inference magic. */
+#ifndef SWAP
+ #define SWAP(x, y) \
+ do { \
+ typeof (x) __tmp = (x); \
+ (x) = (y); \
+ (y) = __tmp; \
+ } while (0)
+#endif
+
+/** Stringify its argument. */
+#define STRINGIFY(x) STRINGIFY_(x)
+#define STRINGIFY_(x) #x
+
+/* Error handling macros.
+ *
+ * These expect a zero = success, non-zero = error convention.
+ */
+
+/** Error: return.
+ *
+ * If the expression fails, return the error from this function. */
+#define ER(expr) do { typeof (expr) err_ = (expr); if (err_) return err_; } while (0)
+
+/** Error: goto.
+ *
+ * If the expression fails, goto x_err. Assumes defn of label
+ * x_err and 'error_type err'. */
+#define EG(expr) do { err = (expr); if (err) goto x_err; } while (0)
+
+/** Like memset(ptr, 0, len), but not allowed to be removed by
+ * compilers. */
+static inline void mem_clean(volatile void *v, size_t len)
+{
+ if (len)
+ {
+ memset((void *) v, 0, len);
+ (void) *((volatile uint8_t *) v);
+ }
+}
+
+/** Returns 1 if len bytes at va equal len bytes at vb, 0 if they do not.
+ * Does not leak length of common prefix through timing. */
+static inline unsigned mem_eq(const void *va, const void *vb, size_t len)
+{
+ const volatile uint8_t *a = va;
+ const volatile uint8_t *b = vb;
+ uint8_t diff = 0;
+
+ while (len--)
+ {
+ diff |= *a++ ^ *b++;
+ }
+
+ return !diff;
+}
+
+#endif
diff --git a/emb/pastilda/lib/crypto/salsa20.h b/emb/pastilda/lib/crypto/salsa20.h
new file mode 100644
index 0000000..2e478b3
--- /dev/null
+++ b/emb/pastilda/lib/crypto/salsa20.h
@@ -0,0 +1,111 @@
+// Copyright (c) 2015 Nezametdinov E. Ildus
+// See LICENSE.TXT for licensing details
+
+#ifndef SALSA20_H
+#define SALSA20_H
+
+#include <cassert>
+#include <climits>
+#include <cstdint>
+#include <cstring>
+
+using std::size_t;
+using std::int32_t;
+using std::uint8_t;
+using std::uint32_t;
+
+/**
+ * Represents Salsa20 cypher. Supports only 256-bit keys.
+ */
+class Salsa20
+{
+public:
+ /// Helper constants
+ enum: size_t
+ {
+ VECTOR_SIZE = 16,
+ BLOCK_SIZE = 64,
+ KEY_SIZE = 32,
+ IV_SIZE = 8
+ };
+
+ /**
+ * \brief Constructs cypher with given key.
+ * \param[in] key 256-bit key
+ */
+ inline Salsa20(const uint8_t* key = nullptr);
+ Salsa20(const Salsa20&) = default;
+ Salsa20(Salsa20&&) = default;
+ ~Salsa20() = default;
+ Salsa20& operator =(const Salsa20&) = default;
+ Salsa20& operator =(Salsa20&&) = default;
+
+ /**
+ * \brief Sets key.
+ * \param[in] key 256-bit key
+ */
+ inline void setKey(const uint8_t* key);
+
+ /**
+ * \brief Sets IV.
+ * \param[in] iv 64-bit IV
+ */
+ inline void setIv(const uint8_t* iv);
+
+ /**
+ * \brief Generates key stream.
+ * \param[out] output generated key stream
+ */
+ inline void generateKeyStream(uint8_t output[BLOCK_SIZE]);
+
+ /**
+ * \brief Processes blocks.
+ * \param[in] input input
+ * \param[out] output output
+ * \param[in] numBlocks number of blocks
+ */
+ inline void processBlocks(const uint8_t* input, uint8_t* output, size_t numBlocks);
+
+ /**
+ * \brief Processes bytes.
+ *
+ * This function should be used carefully. If number of bytes is not multiple of
+ * block size, then next call to the processBlocks function will be invalid.
+ * Normally this function should be used once at the end of encryption or
+ * decryption.
+ * \param[in] input input
+ * \param[out] output output
+ * \param[in] numBytes number of bytes
+ */
+ inline void processBytes(const uint8_t* input, uint8_t* output, size_t numBytes);
+
+private:
+ /**
+ * \brief Rotates value.
+ * \param[in] value value
+ * \param[in] numBits number of bits to rotate
+ * \return result of the rotation
+ */
+ inline uint32_t rotate(uint32_t value, uint32_t numBits);
+
+ /**
+ * \brief Converts 32-bit unsigned integer value to the array of bytes.
+ * \param[in] value 32-bit unsigned integer value
+ * \param[out] array array of bytes
+ */
+ inline void convert(uint32_t value, uint8_t* array);
+
+ /**
+ * \brief Converts array of bytes to the 32-bit unsigned integer value.
+ * \param[in] array array of bytes
+ * \return 32-bit unsigned integer value
+ */
+ inline uint32_t convert(const uint8_t* array);
+
+ // Data members
+ uint32_t vector_[VECTOR_SIZE];
+
+};
+
+#include <salsa20.inl>
+#endif
diff --git a/emb/pastilda/lib/crypto/salsa20.inl b/emb/pastilda/lib/crypto/salsa20.inl
new file mode 100644
index 0000000..1f800c0
--- /dev/null
+++ b/emb/pastilda/lib/crypto/salsa20.inl
@@ -0,0 +1,156 @@
+// Copyright (c) 2015 Nezametdinov E. Ildus
+// See LICENSE.TXT for licensing details
+
+#include "Salsa20.h"
+
+Salsa20::Salsa20(const uint8_t* key)
+{
+ std::memset(vector_, 0, sizeof(vector_));
+ setKey(key);
+}
+
+//----------------------------------------------------------------------------------
+void Salsa20::setKey(const uint8_t* key)
+{
+ static const char constants[] = "expand 32-byte k";
+
+ if(key == nullptr)
+ return;
+
+ vector_[0] = convert(reinterpret_cast<const uint8_t*>(&constants[0]));
+ vector_[1] = convert(&key[0]);
+ vector_[2] = convert(&key[4]);
+ vector_[3] = convert(&key[8]);
+ vector_[4] = convert(&key[12]);
+ vector_[5] = convert(reinterpret_cast<const uint8_t*>(&constants[4]));
+
+ std::memset(&vector_[6], 0, 4 * sizeof(uint32_t));
+
+ vector_[10] = convert(reinterpret_cast<const uint8_t*>(&constants[8]));
+ vector_[11] = convert(&key[16]);
+ vector_[12] = convert(&key[20]);
+ vector_[13] = convert(&key[24]);
+ vector_[14] = convert(&key[28]);
+ vector_[15] = convert(reinterpret_cast<const uint8_t*>(&constants[12]));
+}
+
+//----------------------------------------------------------------------------------
+void Salsa20::setIv(const uint8_t* iv)
+{
+ if(iv == nullptr)
+ return;
+
+ vector_[6] = convert(&iv[0]);
+ vector_[7] = convert(&iv[4]);
+ vector_[8] = vector_[9] = 0;
+}
+
+//----------------------------------------------------------------------------------
+void Salsa20::generateKeyStream(uint8_t output[BLOCK_SIZE])
+{
+ uint32_t x[VECTOR_SIZE];
+ std::memcpy(x, vector_, sizeof(vector_));
+
+ for(int32_t i = 20; i > 0; i -= 2)
+ {
+ x[4 ] ^= rotate(static_cast<uint32_t>(x[0 ] + x[12]), 7);
+ x[8 ] ^= rotate(static_cast<uint32_t>(x[4 ] + x[0 ]), 9);
+ x[12] ^= rotate(static_cast<uint32_t>(x[8 ] + x[4 ]), 13);
+ x[0 ] ^= rotate(static_cast<uint32_t>(x[12] + x[8 ]), 18);
+ x[9 ] ^= rotate(static_cast<uint32_t>(x[5 ] + x[1 ]), 7);
+ x[13] ^= rotate(static_cast<uint32_t>(x[9 ] + x[5 ]), 9);
+ x[1 ] ^= rotate(static_cast<uint32_t>(x[13] + x[9 ]), 13);
+ x[5 ] ^= rotate(static_cast<uint32_t>(x[1 ] + x[13]), 18);
+ x[14] ^= rotate(static_cast<uint32_t>(x[10] + x[6 ]), 7);
+ x[2 ] ^= rotate(static_cast<uint32_t>(x[14] + x[10]), 9);
+ x[6 ] ^= rotate(static_cast<uint32_t>(x[2 ] + x[14]), 13);
+ x[10] ^= rotate(static_cast<uint32_t>(x[6 ] + x[2 ]), 18);
+ x[3 ] ^= rotate(static_cast<uint32_t>(x[15] + x[11]), 7);
+ x[7 ] ^= rotate(static_cast<uint32_t>(x[3 ] + x[15]), 9);
+ x[11] ^= rotate(static_cast<uint32_t>(x[7 ] + x[3 ]), 13);
+ x[15] ^= rotate(static_cast<uint32_t>(x[11] + x[7 ]), 18);
+ x[1 ] ^= rotate(static_cast<uint32_t>(x[0 ] + x[3 ]), 7);
+ x[2 ] ^= rotate(static_cast<uint32_t>(x[1 ] + x[0 ]), 9);
+ x[3 ] ^= rotate(static_cast<uint32_t>(x[2 ] + x[1 ]), 13);
+ x[0 ] ^= rotate(static_cast<uint32_t>(x[3 ] + x[2 ]), 18);
+ x[6 ] ^= rotate(static_cast<uint32_t>(x[5 ] + x[4 ]), 7);
+ x[7 ] ^= rotate(static_cast<uint32_t>(x[6 ] + x[5 ]), 9);
+ x[4 ] ^= rotate(static_cast<uint32_t>(x[7 ] + x[6 ]), 13);
+ x[5 ] ^= rotate(static_cast<uint32_t>(x[4 ] + x[7 ]), 18);
+ x[11] ^= rotate(static_cast<uint32_t>(x[10] + x[9 ]), 7);
+ x[8 ] ^= rotate(static_cast<uint32_t>(x[11] + x[10]), 9);
+ x[9 ] ^= rotate(static_cast<uint32_t>(x[8 ] + x[11]), 13);
+ x[10] ^= rotate(static_cast<uint32_t>(x[9 ] + x[8 ]), 18);
+ x[12] ^= rotate(static_cast<uint32_t>(x[15] + x[14]), 7);
+ x[13] ^= rotate(static_cast<uint32_t>(x[12] + x[15]), 9);
+ x[14] ^= rotate(static_cast<uint32_t>(x[13] + x[12]), 13);
+ x[15] ^= rotate(static_cast<uint32_t>(x[14] + x[13]), 18);
+ }
+
+ for(size_t i = 0; i < VECTOR_SIZE; ++i)
+ {
+ x[i] += vector_[i];
+ convert(x[i], &output[4 * i]);
+ }
+
+ ++vector_[8];
+ vector_[9] += vector_[8] == 0 ? 1 : 0;
+}
+
+//----------------------------------------------------------------------------------
+void Salsa20::processBlocks(const uint8_t* input, uint8_t* output, size_t numBlocks)
+{
+ assert(input != nullptr && output != nullptr);
+
+ uint8_t keyStream[BLOCK_SIZE];
+
+ for(size_t i = 0; i < numBlocks; ++i)
+ {
+ generateKeyStream(keyStream);
+
+ for(size_t j = 0; j < BLOCK_SIZE; ++j)
+ *(output++) = keyStream[j] ^ *(input++);
+ }
+}
+
+//----------------------------------------------------------------------------------
+void Salsa20::processBytes(const uint8_t* input, uint8_t* output, size_t numBytes)
+{
+ assert(input != nullptr && output != nullptr);
+
+ uint8_t keyStream[BLOCK_SIZE];
+ size_t numBytesToProcess;
+
+ while(numBytes != 0)
+ {
+ generateKeyStream(keyStream);
+ numBytesToProcess = numBytes >= BLOCK_SIZE ? BLOCK_SIZE : numBytes;
+
+ for(size_t i = 0; i < numBytesToProcess; ++i, --numBytes)
+ *(output++) = keyStream[i] ^ *(input++);
+ }
+}
+
+//----------------------------------------------------------------------------------
+uint32_t Salsa20::rotate(uint32_t value, uint32_t numBits)
+{
+ return (value << numBits) | (value >> (32 - numBits));
+}
+
+//----------------------------------------------------------------------------------
+void Salsa20::convert(uint32_t value, uint8_t* array)
+{
+ array[0] = static_cast<uint8_t>(value >> 0);
+ array[1] = static_cast<uint8_t>(value >> 8);
+ array[2] = static_cast<uint8_t>(value >> 16);
+ array[3] = static_cast<uint8_t>(value >> 24);
+}
+
+//----------------------------------------------------------------------------------
+uint32_t Salsa20::convert(const uint8_t* array)
+{
+ return ((static_cast<uint32_t>(array[0]) << 0) |
+ (static_cast<uint32_t>(array[1]) << 8) |
+ (static_cast<uint32_t>(array[2]) << 16) |
+ (static_cast<uint32_t>(array[3]) << 24));
+} \ No newline at end of file
diff --git a/emb/pastilda/lib/crypto/sha2.h b/emb/pastilda/lib/crypto/sha2.h
new file mode 100644
index 0000000..f72576f
--- /dev/null
+++ b/emb/pastilda/lib/crypto/sha2.h
@@ -0,0 +1,235 @@
+/*
+ * cifra - embedded cryptography library
+ * Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
+ *
+ * To the extent possible under law, the author(s) have dedicated all
+ * copyright and related and neighboring rights to this software to the
+ * public domain worldwide. This software is distributed without any
+ * warranty.
+ *
+ * You should have received a copy of the CC0 Public Domain Dedication
+ * along with this software. If not, see
+ * <http://creativecommons.org/publicdomain/zero/1.0/>.
+ */
+
+#ifndef SHA2_H
+#define SHA2_H
+
+#include <chash.h>
+#include <stddef.h>
+#include <stdint.h>
+
+
+/**
+ * SHA224/SHA256
+ * =============
+ */
+
+/* .. c:macro:: CF_SHA224_HASHSZ
+ * The output size of SHA224: 28 bytes. */
+#define CF_SHA224_HASHSZ 28
+
+/* .. c:macro:: CF_SHA224_BLOCKSZ
+ * The block size of SHA224: 64 bytes. */
+#define CF_SHA224_BLOCKSZ 64
+
+/* .. c:macro:: CF_SHA256_HASHSZ
+ * The output size of SHA256: 32 bytes. */
+#define CF_SHA256_HASHSZ 32
+
+/* .. c:macro:: CF_SHA256_BLOCKSZ
+ * The block size of SHA256: 64 bytes. */
+#define CF_SHA256_BLOCKSZ 64
+
+/* .. c:type:: cf_sha256_context
+ * Incremental SHA256 hashing context.
+ *
+ * .. c:member:: cf_sha256_context.H
+ * Intermediate values.
+ *
+ * .. c:member:: cf_sha256_context.partial
+ * Unprocessed input.
+ *
+ * .. c:member:: cf_sha256_context.npartial
+ * Number of bytes of unprocessed input.
+ *
+ * .. c:member:: cf_sha256_context.blocks
+ * Number of full blocks processed.
+ */
+typedef struct
+{
+ uint32_t H[8]; /* State. */
+ uint8_t partial[CF_SHA256_BLOCKSZ]; /* Partial block of input. */
+ uint32_t blocks; /* Number of full blocks processed into H. */
+ size_t npartial; /* Number of bytes in prefix of partial. */
+} cf_sha256_context;
+
+/* .. c:function:: $DECL
+ * Sets up `ctx` ready to hash a new message.
+ */
+extern void cf_sha256_init(cf_sha256_context *ctx);
+
+/* .. c:function:: $DECL
+ * Hashes `nbytes` at `data`. Copies the data if there isn't enough to make
+ * a full block.
+ */
+extern void cf_sha256_update(cf_sha256_context *ctx, const void *data, size_t nbytes);
+
+/* .. c:function:: $DECL
+ * Finishes the hash operation, writing `CF_SHA256_HASHSZ` bytes to `hash`.
+ *
+ * This leaves `ctx` unchanged.
+ */
+extern void cf_sha256_digest(const cf_sha256_context *ctx, uint8_t hash[CF_SHA256_HASHSZ]);
+
+/* .. c:function:: $DECL
+ * Finishes the hash operation, writing `CF_SHA256_HASHSZ` bytes to `hash`.
+ *
+ * This destroys `ctx`, but uses less stack than :c:func:`cf_sha256_digest`.
+ */
+extern void cf_sha256_digest_final(cf_sha256_context *ctx, uint8_t hash[CF_SHA256_HASHSZ]);
+
+/* .. c:function:: $DECL
+ * Sets up `ctx` ready to hash a new message.
+ *
+ * nb. SHA224 uses SHA256's underlying types.
+ */
+extern void cf_sha224_init(cf_sha256_context *ctx);
+
+/* .. c:function:: $DECL
+ * Hashes `nbytes` at `data`. Copies the data if there isn't enough to make
+ * a full block.
+ */
+extern void cf_sha224_update(cf_sha256_context *ctx, const void *data, size_t nbytes);
+
+/* .. c:function:: $DECL
+ * Finishes the hash operation, writing `CF_SHA224_HASHSZ` bytes to `hash`.
+ *
+ * This leaves `ctx` unchanged.
+ */
+extern void cf_sha224_digest(const cf_sha256_context *ctx, uint8_t hash[CF_SHA224_HASHSZ]);
+
+/* .. c:function:: $DECL
+ * Finishes the hash operation, writing `CF_SHA224_HASHSZ` bytes to `hash`.
+ *
+ * This destroys `ctx`, but uses less stack than :c:func:`cf_sha224_digest`.
+ */
+extern void cf_sha224_digest_final(cf_sha256_context *ctx, uint8_t hash[CF_SHA224_HASHSZ]);
+
+/* .. c:var:: cf_sha224
+ * Abstract interface to SHA224. See :c:type:`cf_chash` for more information.
+ */
+extern const cf_chash cf_sha224;
+
+/* .. c:var:: cf_sha256
+ * Abstract interface to SHA256. See :c:type:`cf_chash` for more information.
+ */
+extern const cf_chash cf_sha256;
+
+/**
+ * SHA384/SHA512
+ * =============
+ */
+
+/* .. c:macro:: CF_SHA384_HASHSZ
+ * The output size of SHA384: 48 bytes. */
+#define CF_SHA384_HASHSZ 48
+
+/* .. c:macro:: CF_SHA384_BLOCKSZ
+ * The block size of SHA384: 128 bytes. */
+#define CF_SHA384_BLOCKSZ 128
+
+/* .. c:macro:: CF_SHA512_HASHSZ
+ * The output size of SHA512: 64 bytes. */
+#define CF_SHA512_HASHSZ 64
+
+/* .. c:macro:: CF_SHA512_BLOCKSZ
+ * The block size of SHA512: 128 bytes. */
+#define CF_SHA512_BLOCKSZ 128
+
+/* .. c:type:: cf_sha512_context
+ * Incremental SHA512 hashing context.
+ *
+ * .. c:member:: cf_sha512_context.H
+ * Intermediate values.
+ *
+ * .. c:member:: cf_sha512_context.partial
+ * Unprocessed input.
+ *
+ * .. c:member:: cf_sha512_context.npartial
+ * Number of bytes of unprocessed input.
+ *
+ * .. c:member:: cf_sha512_context.blocks
+ * Number of full blocks processed.
+ */
+typedef struct
+{
+ uint64_t H[8];
+ uint8_t partial[CF_SHA512_BLOCKSZ];
+ uint32_t blocks;
+ size_t npartial;
+} cf_sha512_context;
+
+/* .. c:function:: $DECL
+ * Sets up `ctx` ready to hash a new message.
+ */
+extern void cf_sha512_init(cf_sha512_context *ctx);
+
+/* .. c:function:: $DECL
+ * Hashes `nbytes` at `data`. Copies the data if there isn't enough to make
+ * a full block.
+ */
+extern void cf_sha512_update(cf_sha512_context *ctx, const void *data, size_t nbytes);
+
+/* .. c:function:: $DECL
+ * Finishes the hash operation, writing `CF_SHA512_HASHSZ` bytes to `hash`.
+ *
+ * This leaves `ctx` unchanged.
+ */
+extern void cf_sha512_digest(const cf_sha512_context *ctx, uint8_t hash[CF_SHA512_HASHSZ]);
+
+/* .. c:function:: $DECL
+ * Finishes the hash operation, writing `CF_SHA512_HASHSZ` bytes to `hash`.
+ *
+ * This destroys `ctx`, but uses less stack than :c:func:`cf_sha512_digest`.
+ */
+extern void cf_sha512_digest_final(cf_sha512_context *ctx, uint8_t hash[CF_SHA512_HASHSZ]);
+
+/* .. c:function:: $DECL
+ * Sets up `ctx` ready to hash a new message.
+ *
+ * nb. SHA384 uses SHA512's underlying types.
+ */
+extern void cf_sha384_init(cf_sha512_context *ctx);
+
+/* .. c:function:: $DECL
+ * Hashes `nbytes` at `data`. Copies the data if there isn't enough to make
+ * a full block.
+ */
+extern void cf_sha384_update(cf_sha512_context *ctx, const void *data, size_t nbytes);
+
+/* .. c:function:: $DECL
+ * Finishes the hash operation, writing `CF_SHA384_HASHSZ` bytes to `hash`.
+ *
+ * This leaves `ctx` unchanged.
+ */
+extern void cf_sha384_digest(const cf_sha512_context *ctx, uint8_t hash[CF_SHA384_HASHSZ]);
+
+/* .. c:function:: $DECL
+ * Finishes the hash operation, writing `CF_SHA384_HASHSZ` bytes to `hash`.
+ *
+ * This destroys `ctx`, but uses less stack than :c:func:`cf_sha384_digest`.
+ */
+extern void cf_sha384_digest_final(cf_sha512_context *ctx, uint8_t hash[CF_SHA384_HASHSZ]);
+
+/* .. c:var:: cf_sha384
+ * Abstract interface to SHA384. See :c:type:`cf_chash` for more information.
+ */
+extern const cf_chash cf_sha384;
+
+/* .. c:var:: cf_sha512
+ * Abstract interface to SHA512. See :c:type:`cf_chash` for more information.
+ */
+extern const cf_chash cf_sha512;
+
+#endif
diff --git a/emb/pastilda/lib/crypto/sha256.c b/emb/pastilda/lib/crypto/sha256.c
new file mode 100644
index 0000000..88b1db3
--- /dev/null
+++ b/emb/pastilda/lib/crypto/sha256.c
@@ -0,0 +1,230 @@
+/*
+ * cifra - embedded cryptography library
+ * Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
+ *
+ * To the extent possible under law, the author(s) have dedicated all
+ * copyright and related and neighboring rights to this software to the
+ * public domain worldwide. This software is distributed without any
+ * warranty.
+ *
+ * You should have received a copy of the CC0 Public Domain Dedication
+ * along with this software. If not, see
+ * <http://creativecommons.org/publicdomain/zero/1.0/>.
+ */
+
+#include <bitops.h>
+#include <blockwise.h>
+#include <handy.h>
+#include <sha2.h>
+#include <tassert.h>
+#include <string.h>
+
+static const uint32_t K[64] = {
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
+ 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+ 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
+ 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
+ 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+ 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
+ 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
+ 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+ 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+};
+
+# define CH(x, y, z) (((x) & (y)) ^ (~(x) & (z)))
+# define MAJ(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
+# define BSIG0(x) (rotr32((x), 2) ^ rotr32((x), 13) ^ rotr32((x), 22))
+# define BSIG1(x) (rotr32((x), 6) ^ rotr32((x), 11) ^ rotr32((x), 25))
+# define SSIG0(x) (rotr32((x), 7) ^ rotr32((x), 18) ^ ((x) >> 3))
+# define SSIG1(x) (rotr32((x), 17) ^ rotr32((x), 19) ^ ((x) >> 10))
+
+void cf_sha256_init(cf_sha256_context *ctx)
+{
+ memset(ctx, 0, sizeof *ctx);
+ ctx->H[0] = 0x6a09e667;
+ ctx->H[1] = 0xbb67ae85;
+ ctx->H[2] = 0x3c6ef372;
+ ctx->H[3] = 0xa54ff53a;
+ ctx->H[4] = 0x510e527f;
+ ctx->H[5] = 0x9b05688c;
+ ctx->H[6] = 0x1f83d9ab;
+ ctx->H[7] = 0x5be0cd19;
+}
+
+void cf_sha224_init(cf_sha256_context *ctx)
+{
+ memset(ctx, 0, sizeof *ctx);
+ ctx->H[0] = 0xc1059ed8;
+ ctx->H[1] = 0x367cd507;
+ ctx->H[2] = 0x3070dd17;
+ ctx->H[3] = 0xf70e5939;
+ ctx->H[4] = 0xffc00b31;
+ ctx->H[5] = 0x68581511;
+ ctx->H[6] = 0x64f98fa7;
+ ctx->H[7] = 0xbefa4fa4;
+}
+
+static void sha256_update_block(void *vctx, const uint8_t *inp)
+{
+ cf_sha256_context *ctx = vctx;
+
+ /* This is a 16-word window into the whole W array. */
+ uint32_t W[16];
+
+ uint32_t a = ctx->H[0],
+ b = ctx->H[1],
+ c = ctx->H[2],
+ d = ctx->H[3],
+ e = ctx->H[4],
+ f = ctx->H[5],
+ g = ctx->H[6],
+ h = ctx->H[7],
+ Wt;
+
+ for (size_t t = 0; t < 64; t++)
+ {
+ /* For W[0..16] we process the input into W.
+ * For W[16..64] we compute the next W value:
+ *
+ * W[t] = SSIG1(W[t - 2]) + W[t - 7] + SSIG0(W[t - 15]) + W[t - 16];
+ *
+ * But all W indices are reduced mod 16 into our window.
+ */
+ if (t < 16)
+ {
+ W[t] = Wt = read32_be(inp);
+ inp += 4;
+ } else {
+ Wt = SSIG1(W[(t - 2) % 16]) +
+ W[(t - 7) % 16] +
+ SSIG0(W[(t - 15) % 16]) +
+ W[(t - 16) % 16];
+ W[t % 16] = Wt;
+ }
+
+ uint32_t T1 = h + BSIG1(e) + CH(e, f, g) + K[t] + Wt;
+ uint32_t T2 = BSIG0(a) + MAJ(a, b, c);
+ h = g;
+ g = f;
+ f = e;
+ e = d + T1;
+ d = c;
+ c = b;
+ b = a;
+ a = T1 + T2;
+ }
+
+ ctx->H[0] += a;
+ ctx->H[1] += b;
+ ctx->H[2] += c;
+ ctx->H[3] += d;
+ ctx->H[4] += e;
+ ctx->H[5] += f;
+ ctx->H[6] += g;
+ ctx->H[7] += h;
+
+ ctx->blocks++;
+}
+
+void cf_sha256_update(cf_sha256_context *ctx, const void *data, size_t nbytes)
+{
+ cf_blockwise_accumulate(ctx->partial, &ctx->npartial, sizeof ctx->partial,
+ data, nbytes,
+ sha256_update_block, ctx);
+}
+
+void cf_sha224_update(cf_sha256_context *ctx, const void *data, size_t nbytes)
+{
+ cf_sha256_update(ctx, data, nbytes);
+}
+
+void cf_sha256_digest(const cf_sha256_context *ctx, uint8_t hash[CF_SHA256_HASHSZ])
+{
+ /* We copy the context, so the finalisation doesn't effect the caller's
+ * context. This means the caller can do:
+ *
+ * x = init()
+ * x.update('hello')
+ * h1 = x.digest()
+ * x.update(' world')
+ * h2 = x.digest()
+ *
+ * to get h1 = H('hello') and h2 = H('hello world')
+ *
+ * This wouldn't work if we applied MD-padding to *ctx.
+ */
+
+ cf_sha256_context ours = *ctx;
+ cf_sha256_digest_final(&ours, hash);
+}
+
+void cf_sha256_digest_final(cf_sha256_context *ctx, uint8_t hash[CF_SHA256_HASHSZ])
+{
+ uint64_t digested_bytes = ctx->blocks;
+ digested_bytes = digested_bytes * CF_SHA256_BLOCKSZ + ctx->npartial;
+ uint64_t digested_bits = digested_bytes * 8;
+
+ size_t padbytes = CF_SHA256_BLOCKSZ - ((digested_bytes + 8) % CF_SHA256_BLOCKSZ);
+
+ /* Hash 0x80 00 ... block first. */
+ cf_blockwise_acc_pad(ctx->partial, &ctx->npartial, sizeof ctx->partial,
+ 0x80, 0x00, 0x00, padbytes,
+ sha256_update_block, ctx);
+
+ /* Now hash length. */
+ uint8_t buf[8];
+ write64_be(digested_bits, buf);
+ cf_sha256_update(ctx, buf, 8);
+
+ /* We ought to have got our padding calculation right! */
+ assert(ctx->npartial == 0);
+
+ write32_be(ctx->H[0], hash + 0);
+ write32_be(ctx->H[1], hash + 4);
+ write32_be(ctx->H[2], hash + 8);
+ write32_be(ctx->H[3], hash + 12);
+ write32_be(ctx->H[4], hash + 16);
+ write32_be(ctx->H[5], hash + 20);
+ write32_be(ctx->H[6], hash + 24);
+ write32_be(ctx->H[7], hash + 28);
+
+ memset(ctx, 0, sizeof *ctx);
+}
+
+void cf_sha224_digest(const cf_sha256_context *ctx, uint8_t hash[CF_SHA224_HASHSZ])
+{
+ uint8_t full[CF_SHA256_HASHSZ];
+ cf_sha256_digest(ctx, full);
+ memcpy(hash, full, CF_SHA224_HASHSZ);
+}
+
+void cf_sha224_digest_final(cf_sha256_context *ctx, uint8_t hash[CF_SHA224_HASHSZ])
+{
+ uint8_t full[CF_SHA256_HASHSZ];
+ cf_sha256_digest_final(ctx, full);
+ memcpy(hash, full, CF_SHA224_HASHSZ);
+}
+
+const cf_chash cf_sha224 = {
+ .hashsz = CF_SHA224_HASHSZ,
+ .blocksz = CF_SHA256_BLOCKSZ,
+ .init = (cf_chash_init) cf_sha224_init,
+ .update = (cf_chash_update) cf_sha224_update,
+ .digest = (cf_chash_digest) cf_sha224_digest
+};
+
+const cf_chash cf_sha256 = {
+ .hashsz = CF_SHA256_HASHSZ,
+ .blocksz = CF_SHA256_BLOCKSZ,
+ .init = (cf_chash_init) cf_sha256_init,
+ .update = (cf_chash_update) cf_sha256_update,
+ .digest = (cf_chash_digest) cf_sha256_digest
+};
+
diff --git a/emb/pastilda/lib/crypto/tassert.h b/emb/pastilda/lib/crypto/tassert.h
new file mode 100644
index 0000000..58ebb4c
--- /dev/null
+++ b/emb/pastilda/lib/crypto/tassert.h
@@ -0,0 +1,32 @@
+/*
+ * cifra - embedded cryptography library
+ * Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
+ *
+ * To the extent possible under law, the author(s) have dedicated all
+ * copyright and related and neighboring rights to this software to the
+ * public domain worldwide. This software is distributed without any
+ * warranty.
+ *
+ * You should have received a copy of the CC0 Public Domain Dedication
+ * along with this software. If not, see
+ * <http://creativecommons.org/publicdomain/zero/1.0/>.
+ */
+
+#ifndef TASSERT_H
+#define TASSERT_H
+
+/* Tiny assert
+ * -----------
+ *
+ * This is an assert(3) definition which doesn't include any
+ * strings, but just branches to abort(3) on failure.
+ */
+
+#ifndef FULL_FAT_ASSERT
+# include <stdlib.h>
+# define assert(expr) do { if (!(expr)) abort(); } while (0)
+#else
+# include <assert.h>
+#endif
+
+#endif
diff --git a/emb/pastilda/lib/fastdelegate/FastDelegate.h b/emb/pastilda/lib/fastdelegate/FastDelegate.h
new file mode 100644
index 0000000..b6f69d7
--- /dev/null
+++ b/emb/pastilda/lib/fastdelegate/FastDelegate.h
@@ -0,0 +1,2109 @@
+// FastDelegate.h
+// Efficient delegates in C++ that generate only two lines of asm code!
+// Documentation is found at http://www.codeproject.com/cpp/FastDelegate.asp
+//
+// - Don Clugston, Mar 2004.
+// Major contributions were made by Jody Hagins.
+// History:
+// 24-Apr-04 1.0 * Submitted to CodeProject.
+// 28-Apr-04 1.1 * Prevent most unsafe uses of evil static function hack.
+// * Improved syntax for horrible_cast (thanks Paul Bludov).
+// * Tested on Metrowerks MWCC and Intel ICL (IA32)
+// * Compiled, but not run, on Comeau C++ and Intel Itanium ICL.
+// 27-Jun-04 1.2 * Now works on Borland C++ Builder 5.5
+// * Now works on /clr "managed C++" code on VC7, VC7.1
+// * Comeau C++ now compiles without warnings.
+// * Prevent the virtual inheritance case from being used on
+// VC6 and earlier, which generate incorrect code.
+// * Improved warning and error messages. Non-standard hacks
+// now have compile-time checks to make them safer.
+// * implicit_cast used instead of static_cast in many cases.
+// * If calling a const member function, a const class pointer can be used.
+// * MakeDelegate() global helper function added to simplify pass-by-value.
+// * Added fastdelegate.clear()
+// 16-Jul-04 1.2.1* Workaround for gcc bug (const member function pointers in templates)
+// 30-Oct-04 1.3 * Support for (non-void) return values.
+// * No more workarounds in client code!
+// MSVC and Intel now use a clever hack invented by John Dlugosz:
+// - The FASTDELEGATEDECLARE workaround is no longer necessary.
+// - No more warning messages for VC6
+// * Less use of macros. Error messages should be more comprehensible.
+// * Added include guards
+// * Added FastDelegate::empty() to test if invocation is safe (Thanks Neville Franks).
+// * Now tested on VS 2005 Express Beta, PGI C++
+// 24-Dec-04 1.4 * Added DelegateMemento, to allow collections of disparate delegates.
+// * <,>,<=,>= comparison operators to allow storage in ordered containers.
+// * Substantial reduction of code size, especially the 'Closure' class.
+// * Standardised all the compiler-specific workarounds.
+// * MFP conversion now works for CodePlay (but not yet supported in the full code).
+// * Now compiles without warnings on _any_ supported compiler, including BCC 5.5.1
+// * New syntax: FastDelegate< int (char *, double) >.
+// 14-Feb-05 1.4.1* Now treats =0 as equivalent to .clear(), ==0 as equivalent to .empty(). (Thanks elfric).
+// * Now tested on Intel ICL for AMD64, VS2005 Beta for AMD64 and Itanium.
+// 30-Mar-05 1.5 * Safebool idiom: "if (dg)" is now equivalent to "if (!dg.empty())"
+// * Fully supported by CodePlay VectorC
+// * Bugfix for Metrowerks: empty() was buggy because a valid MFP can be 0 on MWCC!
+// * More optimal assignment,== and != operators for static function pointers.
+
+#ifndef FASTDELEGATE_H
+#define FASTDELEGATE_H
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#include <memory> // to allow <,> comparisons
+#include <cstring>
+
+////////////////////////////////////////////////////////////////////////////////
+// Configuration options
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// Uncomment the following #define for optimally-sized delegates.
+// In this case, the generated asm code is almost identical to the code you'd get
+// if the compiler had native support for delegates.
+// It will not work on systems where sizeof(dataptr) < sizeof(codeptr).
+// Thus, it will not work for DOS compilers using the medium model.
+// It will also probably fail on some DSP systems.
+#define FASTDELEGATE_USESTATICFUNCTIONHACK
+
+// Uncomment the next line to allow function declarator syntax.
+// It is automatically enabled for those compilers where it is known to work.
+//#define FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX
+
+////////////////////////////////////////////////////////////////////////////////
+// Compiler identification for workarounds
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// Compiler identification. It's not easy to identify Visual C++ because
+// many vendors fraudulently define Microsoft's identifiers.
+#if defined(_MSC_VER) && !defined(__MWERKS__) && !defined(__VECTOR_C) && !defined(__ICL) && !defined(__BORLANDC__)
+#define FASTDLGT_ISMSVC
+
+#if (_MSC_VER <1300) // Many workarounds are required for VC6.
+#define FASTDLGT_VC6
+#pragma warning(disable:4786) // disable this ridiculous warning
+#endif
+
+#endif
+
+// Does the compiler uses Microsoft's member function pointer structure?
+// If so, it needs special treatment.
+// Metrowerks CodeWarrior, Intel, and CodePlay fraudulently define Microsoft's
+// identifier, _MSC_VER. We need to filter Metrowerks out.
+#if defined(_MSC_VER) && !defined(__MWERKS__)
+#define FASTDLGT_MICROSOFT_MFP
+
+#if !defined(__VECTOR_C)
+// CodePlay doesn't have the __single/multi/virtual_inheritance keywords
+#define FASTDLGT_HASINHERITANCE_KEYWORDS
+#endif
+#endif
+
+// Does it allow function declarator syntax? The following compilers are known to work:
+#if defined(FASTDLGT_ISMSVC) && (_MSC_VER >=1310) // VC 7.1
+#define FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX
+#endif
+
+// Gcc(2.95+), and versions of Digital Mars, Intel and Comeau in common use.
+#if defined (__DMC__) || defined(__GNUC__) || defined(__ICL) || defined(__COMO__)
+#define FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX
+#endif
+
+// It works on Metrowerks MWCC 3.2.2. From boost.Config it should work on earlier ones too.
+#if defined (__MWERKS__)
+#define FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX
+#endif
+
+#ifdef __GNUC__ // Workaround GCC bug #8271
+ // At present, GCC doesn't recognize constness of MFPs in templates
+#define FASTDELEGATE_GCC_BUG_8271
+#endif
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// General tricks used in this code
+//
+// (a) Error messages are generated by typdefing an array of negative size to
+// generate compile-time errors.
+// (b) Warning messages on MSVC are generated by declaring unused variables, and
+// enabling the "variable XXX is never used" warning.
+// (c) Unions are used in a few compiler-specific cases to perform illegal casts.
+// (d) For Microsoft and Intel, when adjusting the 'this' pointer, it's cast to
+// (char *) first to ensure that the correct number of *bytes* are added.
+//
+////////////////////////////////////////////////////////////////////////////////
+// Helper templates
+//
+////////////////////////////////////////////////////////////////////////////////
+
+
+namespace fastdelegate {
+namespace detail { // we'll hide the implementation details in a nested namespace.
+
+// implicit_cast< >
+// I believe this was originally going to be in the C++ standard but
+// was left out by accident. It's even milder than static_cast.
+// I use it instead of static_cast<> to emphasize that I'm not doing
+// anything nasty.
+// Usage is identical to static_cast<>
+template <class OutputClass, class InputClass>
+inline OutputClass implicit_cast(InputClass input){
+ return input;
+}
+
+// horrible_cast< >
+// This is truly evil. It completely subverts C++'s type system, allowing you
+// to cast from any class to any other class. Technically, using a union
+// to perform the cast is undefined behaviour (even in C). But we can see if
+// it is OK by checking that the union is the same size as each of its members.
+// horrible_cast<> should only be used for compiler-specific workarounds.
+// Usage is identical to reinterpret_cast<>.
+
+// This union is declared outside the horrible_cast because BCC 5.5.1
+// can't inline a function with a nested class, and gives a warning.
+template <class OutputClass, class InputClass>
+union horrible_union{
+ OutputClass out;
+ InputClass in;
+};
+
+template <class OutputClass, class InputClass>
+inline OutputClass horrible_cast(const InputClass input){
+ horrible_union<OutputClass, InputClass> u;
+ // Cause a compile-time error if in, out and u are not the same size.
+ // If the compile fails here, it means the compiler has peculiar
+ // unions which would prevent the cast from working.
+ typedef int ERROR_CantUseHorrible_cast[sizeof(InputClass)==sizeof(u)
+ && sizeof(InputClass)==sizeof(OutputClass) ? 1 : -1];
+ u.in = input;
+ return u.out;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Workarounds
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// Backwards compatibility: This macro used to be necessary in the virtual inheritance
+// case for Intel and Microsoft. Now it just forward-declares the class.
+#define FASTDELEGATEDECLARE(CLASSNAME) class CLASSNAME;
+
+// Prevent use of the static function hack with the DOS medium model.
+#ifdef __MEDIUM__
+#undef FASTDELEGATE_USESTATICFUNCTIONHACK
+#endif
+
+// DefaultVoid - a workaround for 'void' templates in VC6.
+//
+// (1) VC6 and earlier do not allow 'void' as a default template argument.
+// (2) They also doesn't allow you to return 'void' from a function.
+//
+// Workaround for (1): Declare a dummy type 'DefaultVoid' which we use
+// when we'd like to use 'void'. We convert it into 'void' and back
+// using the templates DefaultVoidToVoid<> and VoidToDefaultVoid<>.
+// Workaround for (2): On VC6, the code for calling a void function is
+// identical to the code for calling a non-void function in which the
+// return value is never used, provided the return value is returned
+// in the EAX register, rather than on the stack.
+// This is true for most fundamental types such as int, enum, void *.
+// Const void * is the safest option since it doesn't participate
+// in any automatic conversions. But on a 16-bit compiler it might
+// cause extra code to be generated, so we disable it for all compilers
+// except for VC6 (and VC5).
+#ifdef FASTDLGT_VC6
+// VC6 workaround
+typedef const void * DefaultVoid;
+#else
+// On any other compiler, just use a normal void.
+typedef void DefaultVoid;
+#endif
+
+// Translate from 'DefaultVoid' to 'void'.
+// Everything else is unchanged
+template <class T>
+struct DefaultVoidToVoid { typedef T type; };
+
+template <>
+struct DefaultVoidToVoid<DefaultVoid> { typedef void type; };
+
+// Translate from 'void' into 'DefaultVoid'
+// Everything else is unchanged
+template <class T>
+struct VoidToDefaultVoid { typedef T type; };
+
+template <>
+struct VoidToDefaultVoid<void> { typedef DefaultVoid type; };
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Fast Delegates, part 1:
+//
+// Conversion of member function pointer to a standard form
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// GenericClass is a fake class, ONLY used to provide a type.
+// It is vitally important that it is never defined, so that the compiler doesn't
+// think it can optimize the invocation. For example, Borland generates simpler
+// code if it knows the class only uses single inheritance.
+
+// Compilers using Microsoft's structure need to be treated as a special case.
+#ifdef FASTDLGT_MICROSOFT_MFP
+
+#ifdef FASTDLGT_HASINHERITANCE_KEYWORDS
+ // For Microsoft and Intel, we want to ensure that it's the most efficient type of MFP
+ // (4 bytes), even when the /vmg option is used. Declaring an empty class
+ // would give 16 byte pointers in this case....
+ class __single_inheritance GenericClass;
+#endif
+ // ...but for Codeplay, an empty class *always* gives 4 byte pointers.
+ // If compiled with the /clr option ("managed C++"), the JIT compiler thinks
+ // it needs to load GenericClass before it can call any of its functions,
+ // (compiles OK but crashes at runtime!), so we need to declare an
+ // empty class to make it happy.
+ // Codeplay and VC4 can't cope with the unknown_inheritance case either.
+ class GenericClass {};
+#else
+ class GenericClass;
+#endif
+
+// The size of a single inheritance member function pointer.
+const int SINGLE_MEMFUNCPTR_SIZE = sizeof(void (GenericClass::*)());
+
+// SimplifyMemFunc< >::Convert()
+//
+// A template function that converts an arbitrary member function pointer into the
+// simplest possible form of member function pointer, using a supplied 'this' pointer.
+// According to the standard, this can be done legally with reinterpret_cast<>.
+// For (non-standard) compilers which use member function pointers which vary in size
+// depending on the class, we need to use knowledge of the internal structure of a
+// member function pointer, as used by the compiler. Template specialization is used
+// to distinguish between the sizes. Because some compilers don't support partial
+// template specialisation, I use full specialisation of a wrapper struct.
+
+// general case -- don't know how to convert it. Force a compile failure
+template <int N>
+struct SimplifyMemFunc {
+ template <class X, class XFuncType, class GenericMemFuncType>
+ inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind,
+ GenericMemFuncType &bound_func) {
+ // Unsupported member function type -- force a compile failure.
+ // (it's illegal to have a array with negative size).
+ typedef char ERROR_Unsupported_member_function_pointer_on_this_compiler[N-100];
+ return 0;
+ }
+};
+
+// For compilers where all member func ptrs are the same size, everything goes here.
+// For non-standard compilers, only single_inheritance classes go here.
+template <>
+struct SimplifyMemFunc<SINGLE_MEMFUNCPTR_SIZE> {
+ template <class X, class XFuncType, class GenericMemFuncType>
+ inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind,
+ GenericMemFuncType &bound_func) {
+#if defined __DMC__
+ // Digital Mars doesn't allow you to cast between abitrary PMF's,
+ // even though the standard says you can. The 32-bit compiler lets you
+ // static_cast through an int, but the DOS compiler doesn't.
+ bound_func = horrible_cast<GenericMemFuncType>(function_to_bind);
+#else
+ bound_func = reinterpret_cast<GenericMemFuncType>(function_to_bind);
+#endif
+ return reinterpret_cast<GenericClass *>(pthis);
+ }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Fast Delegates, part 1b:
+//
+// Workarounds for Microsoft and Intel
+//
+////////////////////////////////////////////////////////////////////////////////
+
+
+// Compilers with member function pointers which violate the standard (MSVC, Intel, Codeplay),
+// need to be treated as a special case.
+#ifdef FASTDLGT_MICROSOFT_MFP
+
+// We use unions to perform horrible_casts. I would like to use #pragma pack(push, 1)
+// at the start of each function for extra safety, but VC6 seems to ICE
+// intermittently if you do this inside a template.
+
+// __multiple_inheritance classes go here
+// Nasty hack for Microsoft and Intel (IA32 and Itanium)
+template<>
+struct SimplifyMemFunc< SINGLE_MEMFUNCPTR_SIZE + sizeof(int) > {
+ template <class X, class XFuncType, class GenericMemFuncType>
+ inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind,
+ GenericMemFuncType &bound_func) {
+ // We need to use a horrible_cast to do this conversion.
+ // In MSVC, a multiple inheritance member pointer is internally defined as:
+ union {
+ XFuncType func;
+ struct {
+ GenericMemFuncType funcaddress; // points to the actual member function
+ int delta; // #BYTES to be added to the 'this' pointer
+ }s;
+ } u;
+ // Check that the horrible_cast will work
+ typedef int ERROR_CantUsehorrible_cast[sizeof(function_to_bind)==sizeof(u.s)? 1 : -1];
+ u.func = function_to_bind;
+ bound_func = u.s.funcaddress;
+ return reinterpret_cast<GenericClass *>(reinterpret_cast<char *>(pthis) + u.s.delta);
+ }
+};
+
+// virtual inheritance is a real nuisance. It's inefficient and complicated.
+// On MSVC and Intel, there isn't enough information in the pointer itself to
+// enable conversion to a closure pointer. Earlier versions of this code didn't
+// work for all cases, and generated a compile-time error instead.
+// But a very clever hack invented by John M. Dlugosz solves this problem.
+// My code is somewhat different to his: I have no asm code, and I make no
+// assumptions about the calling convention that is used.
+
+// In VC++ and ICL, a virtual_inheritance member pointer
+// is internally defined as:
+struct MicrosoftVirtualMFP {
+ void (GenericClass::*codeptr)(); // points to the actual member function
+ int delta; // #bytes to be added to the 'this' pointer
+ int vtable_index; // or 0 if no virtual inheritance
+};
+// The CRUCIAL feature of Microsoft/Intel MFPs which we exploit is that the
+// m_codeptr member is *always* called, regardless of the values of the other
+// members. (This is *not* true for other compilers, eg GCC, which obtain the
+// function address from the vtable if a virtual function is being called).
+// Dlugosz's trick is to make the codeptr point to a probe function which
+// returns the 'this' pointer that was used.
+
+// Define a generic class that uses virtual inheritance.
+// It has a trival member function that returns the value of the 'this' pointer.
+struct GenericVirtualClass : virtual public GenericClass
+{
+ typedef GenericVirtualClass * (GenericVirtualClass::*ProbePtrType)();
+ GenericVirtualClass * GetThis() { return this; }
+};
+
+// __virtual_inheritance classes go here
+template <>
+struct SimplifyMemFunc<SINGLE_MEMFUNCPTR_SIZE + 2*sizeof(int) >
+{
+
+ template <class X, class XFuncType, class GenericMemFuncType>
+ inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind,
+ GenericMemFuncType &bound_func) {
+ union {
+ XFuncType func;
+ GenericClass* (X::*ProbeFunc)();
+ MicrosoftVirtualMFP s;
+ } u;
+ u.func = function_to_bind;
+ bound_func = reinterpret_cast<GenericMemFuncType>(u.s.codeptr);
+ union {
+ GenericVirtualClass::ProbePtrType virtfunc;
+ MicrosoftVirtualMFP s;
+ } u2;
+ // Check that the horrible_cast<>s will work
+ typedef int ERROR_CantUsehorrible_cast[sizeof(function_to_bind)==sizeof(u.s)
+ && sizeof(function_to_bind)==sizeof(u.ProbeFunc)
+ && sizeof(u2.virtfunc)==sizeof(u2.s) ? 1 : -1];
+ // Unfortunately, taking the address of a MF prevents it from being inlined, so
+ // this next line can't be completely optimised away by the compiler.
+ u2.virtfunc = &GenericVirtualClass::GetThis;
+ u.s.codeptr = u2.s.codeptr;
+ return (pthis->*u.ProbeFunc)();
+ }
+};
+
+#if (_MSC_VER <1300)
+
+// Nasty hack for Microsoft Visual C++ 6.0
+// unknown_inheritance classes go here
+// There is a compiler bug in MSVC6 which generates incorrect code in this case!!
+template <>
+struct SimplifyMemFunc<SINGLE_MEMFUNCPTR_SIZE + 3*sizeof(int) >
+{
+ template <class X, class XFuncType, class GenericMemFuncType>
+ inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind,
+ GenericMemFuncType &bound_func) {
+ // There is an apalling but obscure compiler bug in MSVC6 and earlier:
+ // vtable_index and 'vtordisp' are always set to 0 in the
+ // unknown_inheritance case!
+ // This means that an incorrect function could be called!!!
+ // Compiling with the /vmg option leads to potentially incorrect code.
+ // This is probably the reason that the IDE has a user interface for specifying
+ // the /vmg option, but it is disabled - you can only specify /vmg on
+ // the command line. In VC1.5 and earlier, the compiler would ICE if it ever
+ // encountered this situation.
+ // It is OK to use the /vmg option if /vmm or /vms is specified.
+
+ // Fortunately, the wrong function is only called in very obscure cases.
+ // It only occurs when a derived class overrides a virtual function declared
+ // in a virtual base class, and the member function
+ // points to the *Derived* version of that function. The problem can be
+ // completely averted in 100% of cases by using the *Base class* for the
+ // member fpointer. Ie, if you use the base class as an interface, you'll
+ // stay out of trouble.
+ // Occasionally, you might want to point directly to a derived class function
+ // that isn't an override of a base class. In this case, both vtable_index
+ // and 'vtordisp' are zero, but a virtual_inheritance pointer will be generated.
+ // We can generate correct code in this case. To prevent an incorrect call from
+ // ever being made, on MSVC6 we generate a warning, and call a function to
+ // make the program crash instantly.
+ typedef char ERROR_VC6CompilerBug[-100];
+ return 0;
+ }
+};
+
+
+#else
+
+// Nasty hack for Microsoft and Intel (IA32 and Itanium)
+// unknown_inheritance classes go here
+// This is probably the ugliest bit of code I've ever written. Look at the casts!
+// There is a compiler bug in MSVC6 which prevents it from using this code.
+template <>
+struct SimplifyMemFunc<SINGLE_MEMFUNCPTR_SIZE + 3*sizeof(int) >
+{
+ template <class X, class XFuncType, class GenericMemFuncType>
+ inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind,
+ GenericMemFuncType &bound_func) {
+ // The member function pointer is 16 bytes long. We can't use a normal cast, but
+ // we can use a union to do the conversion.
+ union {
+ XFuncType func;
+ // In VC++ and ICL, an unknown_inheritance member pointer
+ // is internally defined as:
+ struct {
+ GenericMemFuncType m_funcaddress; // points to the actual member function
+ int delta; // #bytes to be added to the 'this' pointer
+ int vtordisp; // #bytes to add to 'this' to find the vtable
+ int vtable_index; // or 0 if no virtual inheritance
+ } s;
+ } u;
+ // Check that the horrible_cast will work
+ typedef int ERROR_CantUsehorrible_cast[sizeof(XFuncType)==sizeof(u.s)? 1 : -1];
+ u.func = function_to_bind;
+ bound_func = u.s.funcaddress;
+ int virtual_delta = 0;
+ if (u.s.vtable_index) { // Virtual inheritance is used
+ // First, get to the vtable.
+ // It is 'vtordisp' bytes from the start of the class.
+ const int * vtable = *reinterpret_cast<const int *const*>(
+ reinterpret_cast<const char *>(pthis) + u.s.vtordisp );
+
+ // 'vtable_index' tells us where in the table we should be looking.
+ virtual_delta = u.s.vtordisp + *reinterpret_cast<const int *>(
+ reinterpret_cast<const char *>(vtable) + u.s.vtable_index);
+ }
+ // The int at 'virtual_delta' gives us the amount to add to 'this'.
+ // Finally we can add the three components together. Phew!
+ return reinterpret_cast<GenericClass *>(
+ reinterpret_cast<char *>(pthis) + u.s.delta + virtual_delta);
+ };
+};
+#endif // MSVC 7 and greater
+
+#endif // MS/Intel hacks
+
+} // namespace detail
+
+////////////////////////////////////////////////////////////////////////////////
+// Fast Delegates, part 2:
+//
+// Define the delegate storage, and cope with static functions
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// DelegateMemento -- an opaque structure which can hold an arbitary delegate.
+// It knows nothing about the calling convention or number of arguments used by
+// the function pointed to.
+// It supplies comparison operators so that it can be stored in STL collections.
+// It cannot be set to anything other than null, nor invoked directly:
+// it must be converted to a specific delegate.
+
+// Implementation:
+// There are two possible implementations: the Safe method and the Evil method.
+// DelegateMemento - Safe version
+//
+// This implementation is standard-compliant, but a bit tricky.
+// A static function pointer is stored inside the class.
+// Here are the valid values:
+// +-- Static pointer --+--pThis --+-- pMemFunc-+-- Meaning------+
+// | 0 | 0 | 0 | Empty |
+// | !=0 |(dontcare)| Invoker | Static function|
+// | 0 | !=0 | !=0* | Method call |
+// +--------------------+----------+------------+----------------+
+// * For Metrowerks, this can be 0. (first virtual function in a
+// single_inheritance class).
+// When stored stored inside a specific delegate, the 'dontcare' entries are replaced
+// with a reference to the delegate itself. This complicates the = and == operators
+// for the delegate class.
+
+// DelegateMemento - Evil version
+//
+// For compilers where data pointers are at least as big as code pointers, it is
+// possible to store the function pointer in the this pointer, using another
+// horrible_cast. In this case the DelegateMemento implementation is simple:
+// +--pThis --+-- pMemFunc-+-- Meaning---------------------+
+// | 0 | 0 | Empty |
+// | !=0 | !=0* | Static function or method call|
+// +----------+------------+-------------------------------+
+// * For Metrowerks, this can be 0. (first virtual function in a
+// single_inheritance class).
+// Note that the Sun C++ and MSVC documentation explicitly state that they
+// support static_cast between void * and function pointers.
+
+class DelegateMemento {
+protected:
+ // the data is protected, not private, because many
+ // compilers have problems with template friends.
+ typedef void (detail::GenericClass::*GenericMemFuncType)(); // arbitrary MFP.
+ detail::GenericClass *m_pthis;
+ GenericMemFuncType m_pFunction;
+
+#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)
+ typedef void (*GenericFuncPtr)(); // arbitrary code pointer
+ GenericFuncPtr m_pStaticFunction;
+#endif
+
+public:
+#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)
+ DelegateMemento() : m_pthis(0), m_pFunction(0), m_pStaticFunction(0) {};
+ void clear() {
+ m_pthis=0; m_pFunction=0; m_pStaticFunction=0;
+ }
+#else
+ DelegateMemento() : m_pthis(0), m_pFunction(0) {};
+ void clear() { m_pthis=0; m_pFunction=0; }
+#endif
+public:
+#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)
+ inline bool IsEqual (const DelegateMemento &x) const{
+ // We have to cope with the static function pointers as a special case
+ if (m_pFunction!=x.m_pFunction) return false;
+ // the static function ptrs must either both be equal, or both be 0.
+ if (m_pStaticFunction!=x.m_pStaticFunction) return false;
+ if (m_pStaticFunction!=0) return m_pthis==x.m_pthis;
+ else return true;
+ }
+#else // Evil Method
+ inline bool IsEqual (const DelegateMemento &x) const{
+ return m_pthis==x.m_pthis && m_pFunction==x.m_pFunction;
+ }
+#endif
+ // Provide a strict weak ordering for DelegateMementos.
+ inline bool IsLess(const DelegateMemento &right) const {
+ // deal with static function pointers first
+#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)
+ if (m_pStaticFunction !=0 || right.m_pStaticFunction!=0)
+ return m_pStaticFunction < right.m_pStaticFunction;
+#endif
+ if (m_pthis !=right.m_pthis) return m_pthis < right.m_pthis;
+ // There are no ordering operators for member function pointers,
+ // but we can fake one by comparing each byte. The resulting ordering is
+ // arbitrary (and compiler-dependent), but it permits storage in ordered STL containers.
+ return memcmp(&m_pFunction, &right.m_pFunction, sizeof(m_pFunction)) < 0;
+
+ }
+ // BUGFIX (Mar 2005):
+ // We can't just compare m_pFunction because on Metrowerks,
+ // m_pFunction can be zero even if the delegate is not empty!
+ inline bool operator ! () const // Is it bound to anything?
+ { return m_pthis==0 && m_pFunction==0; }
+ inline bool empty() const // Is it bound to anything?
+ { return m_pthis==0 && m_pFunction==0; }
+public:
+ DelegateMemento & operator = (const DelegateMemento &right) {
+ SetMementoFrom(right);
+ return *this;
+ }
+ inline bool operator <(const DelegateMemento &right) {
+ return IsLess(right);
+ }
+ inline bool operator >(const DelegateMemento &right) {
+ return right.IsLess(*this);
+ }
+ DelegateMemento (const DelegateMemento &right) :
+ m_pFunction(right.m_pFunction), m_pthis(right.m_pthis)
+#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)
+ , m_pStaticFunction (right.m_pStaticFunction)
+#endif
+ {}
+protected:
+ void SetMementoFrom(const DelegateMemento &right) {
+ m_pFunction = right.m_pFunction;
+ m_pthis = right.m_pthis;
+#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)
+ m_pStaticFunction = right.m_pStaticFunction;
+#endif
+ }
+};
+
+
+// ClosurePtr<>
+//
+// A private wrapper class that adds function signatures to DelegateMemento.
+// It's the class that does most of the actual work.
+// The signatures are specified by:
+// GenericMemFunc: must be a type of GenericClass member function pointer.
+// StaticFuncPtr: must be a type of function pointer with the same signature
+// as GenericMemFunc.
+// UnvoidStaticFuncPtr: is the same as StaticFuncPtr, except on VC6
+// where it never returns void (returns DefaultVoid instead).
+
+// An outer class, FastDelegateN<>, handles the invoking and creates the
+// necessary typedefs.
+// This class does everything else.
+
+namespace detail {
+
+template < class GenericMemFunc, class StaticFuncPtr, class UnvoidStaticFuncPtr>
+class ClosurePtr : public DelegateMemento {
+public:
+ // These functions are for setting the delegate to a member function.
+
+ // Here's the clever bit: we convert an arbitrary member function into a
+ // standard form. XMemFunc should be a member function of class X, but I can't
+ // enforce that here. It needs to be enforced by the wrapper class.
+ template < class X, class XMemFunc >
+ inline void bindmemfunc(X *pthis, XMemFunc function_to_bind ) {
+ m_pthis = SimplifyMemFunc< sizeof(function_to_bind) >
+ ::Convert(pthis, function_to_bind, m_pFunction);
+#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)
+ m_pStaticFunction = 0;
+#endif
+ }
+ // For const member functions, we only need a const class pointer.
+ // Since we know that the member function is const, it's safe to
+ // remove the const qualifier from the 'this' pointer with a const_cast.
+ // VC6 has problems if we just overload 'bindmemfunc', so we give it a different name.
+ template < class X, class XMemFunc>
+ inline void bindconstmemfunc(const X *pthis, XMemFunc function_to_bind) {
+ m_pthis= SimplifyMemFunc< sizeof(function_to_bind) >
+ ::Convert(const_cast<X*>(pthis), function_to_bind, m_pFunction);
+#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)
+ m_pStaticFunction = 0;
+#endif
+ }
+#ifdef FASTDELEGATE_GCC_BUG_8271 // At present, GCC doesn't recognize constness of MFPs in templates
+ template < class X, class XMemFunc>
+ inline void bindmemfunc(const X *pthis, XMemFunc function_to_bind) {
+ bindconstmemfunc(pthis, function_to_bind);
+#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)
+ m_pStaticFunction = 0;
+#endif
+ }
+#endif
+ // These functions are required for invoking the stored function
+ inline GenericClass *GetClosureThis() const { return m_pthis; }
+ inline GenericMemFunc GetClosureMemPtr() const { return reinterpret_cast<GenericMemFunc>(m_pFunction); }
+
+// There are a few ways of dealing with static function pointers.
+// There's a standard-compliant, but tricky method.
+// There's also a straightforward hack, that won't work on DOS compilers using the
+// medium memory model. It's so evil that I can't recommend it, but I've
+// implemented it anyway because it produces very nice asm code.
+
+#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)
+
+// ClosurePtr<> - Safe version
+//
+// This implementation is standard-compliant, but a bit tricky.
+// I store the function pointer inside the class, and the delegate then
+// points to itself. Whenever the delegate is copied, these self-references
+// must be transformed, and this complicates the = and == operators.
+public:
+ // The next two functions are for operator ==, =, and the copy constructor.
+ // We may need to convert the m_pthis pointers, so that
+ // they remain as self-references.
+ template< class DerivedClass >
+ inline void CopyFrom (DerivedClass *pParent, const DelegateMemento &x) {
+ SetMementoFrom(x);
+ if (m_pStaticFunction!=0) {
+ // transform self references...
+ m_pthis=reinterpret_cast<GenericClass *>(pParent);
+ }
+ }
+ // For static functions, the 'static_function_invoker' class in the parent
+ // will be called. The parent then needs to call GetStaticFunction() to find out
+ // the actual function to invoke.
+ template < class DerivedClass, class ParentInvokerSig >
+ inline void bindstaticfunc(DerivedClass *pParent, ParentInvokerSig static_function_invoker,
+ StaticFuncPtr function_to_bind ) {
+ if (function_to_bind==0) { // cope with assignment to 0
+ m_pFunction=0;
+ } else {
+ bindmemfunc(pParent, static_function_invoker);
+ }
+ m_pStaticFunction=reinterpret_cast<GenericFuncPtr>(function_to_bind);
+ }
+ inline UnvoidStaticFuncPtr GetStaticFunction() const {
+ return reinterpret_cast<UnvoidStaticFuncPtr>(m_pStaticFunction);
+ }
+#else
+
+// ClosurePtr<> - Evil version
+//
+// For compilers where data pointers are at least as big as code pointers, it is
+// possible to store the function pointer in the this pointer, using another
+// horrible_cast. Invocation isn't any faster, but it saves 4 bytes, and
+// speeds up comparison and assignment. If C++ provided direct language support
+// for delegates, they would produce asm code that was almost identical to this.
+// Note that the Sun C++ and MSVC documentation explicitly state that they
+// support static_cast between void * and function pointers.
+
+ template< class DerivedClass >
+ inline void CopyFrom (DerivedClass *pParent, const DelegateMemento &right) {
+ SetMementoFrom(right);
+ }
+ // For static functions, the 'static_function_invoker' class in the parent
+ // will be called. The parent then needs to call GetStaticFunction() to find out
+ // the actual function to invoke.
+ // ******** EVIL, EVIL CODE! *******
+ template < class DerivedClass, class ParentInvokerSig>
+ inline void bindstaticfunc(DerivedClass *pParent, ParentInvokerSig static_function_invoker,
+ StaticFuncPtr function_to_bind) {
+ if (function_to_bind==0) { // cope with assignment to 0
+ m_pFunction=0;
+ } else {
+ // We'll be ignoring the 'this' pointer, but we need to make sure we pass
+ // a valid value to bindmemfunc().
+ bindmemfunc(pParent, static_function_invoker);
+ }
+
+ // WARNING! Evil hack. We store the function in the 'this' pointer!
+ // Ensure that there's a compilation failure if function pointers
+ // and data pointers have different sizes.
+ // If you get this error, you need to #undef FASTDELEGATE_USESTATICFUNCTIONHACK.
+ typedef int ERROR_CantUseEvilMethod[sizeof(GenericClass *)==sizeof(function_to_bind) ? 1 : -1];
+ m_pthis = horrible_cast<GenericClass *>(function_to_bind);
+ // MSVC, SunC++ and DMC accept the following (non-standard) code:
+// m_pthis = static_cast<GenericClass *>(static_cast<void *>(function_to_bind));
+ // BCC32, Comeau and DMC accept this method. MSVC7.1 needs __int64 instead of long
+// m_pthis = reinterpret_cast<GenericClass *>(reinterpret_cast<long>(function_to_bind));
+ }
+ // ******** EVIL, EVIL CODE! *******
+ // This function will be called with an invalid 'this' pointer!!
+ // We're just returning the 'this' pointer, converted into
+ // a function pointer!
+ inline UnvoidStaticFuncPtr GetStaticFunction() const {
+ // Ensure that there's a compilation failure if function pointers
+ // and data pointers have different sizes.
+ // If you get this error, you need to #undef FASTDELEGATE_USESTATICFUNCTIONHACK.
+ typedef int ERROR_CantUseEvilMethod[sizeof(UnvoidStaticFuncPtr)==sizeof(this) ? 1 : -1];
+ return horrible_cast<UnvoidStaticFuncPtr>(this);
+ }
+#endif // !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)
+
+ // Does the closure contain this static function?
+ inline bool IsEqualToStaticFuncPtr(StaticFuncPtr funcptr){
+ if (funcptr==0) return empty();
+ // For the Evil method, if it doesn't actually contain a static function, this will return an arbitrary
+ // value that is not equal to any valid function pointer.
+ else return funcptr==reinterpret_cast<StaticFuncPtr>(GetStaticFunction());
+ }
+};
+
+
+} // namespace detail
+
+////////////////////////////////////////////////////////////////////////////////
+// Fast Delegates, part 3:
+//
+// Wrapper classes to ensure type safety
+//
+////////////////////////////////////////////////////////////////////////////////
+
+
+// Once we have the member function conversion templates, it's easy to make the
+// wrapper classes. So that they will work with as many compilers as possible,
+// the classes are of the form
+// FastDelegate3<int, char *, double>
+// They can cope with any combination of parameters. The max number of parameters
+// allowed is 8, but it is trivial to increase this limit.
+// Note that we need to treat const member functions seperately.
+// All this class does is to enforce type safety, and invoke the delegate with
+// the correct list of parameters.
+
+// Because of the weird rule about the class of derived member function pointers,
+// you sometimes need to apply a downcast to the 'this' pointer.
+// This is the reason for the use of "implicit_cast<X*>(pthis)" in the code below.
+// If CDerivedClass is derived from CBaseClass, but doesn't override SimpleVirtualFunction,
+// without this trick you'd need to write:
+// MyDelegate(static_cast<CBaseClass *>(&d), &CDerivedClass::SimpleVirtualFunction);
+// but with the trick you can write
+// MyDelegate(&d, &CDerivedClass::SimpleVirtualFunction);
+
+// RetType is the type the compiler uses in compiling the template. For VC6,
+// it cannot be void. DesiredRetType is the real type which is returned from
+// all of the functions. It can be void.
+
+// Implicit conversion to "bool" is achieved using the safe_bool idiom,
+// using member data pointers (MDP). This allows "if (dg)..." syntax
+// Because some compilers (eg codeplay) don't have a unique value for a zero
+// MDP, an extra padding member is added to the SafeBool struct.
+// Some compilers (eg VC6) won't implicitly convert from 0 to an MDP, so
+// in that case the static function constructor is not made explicit; this
+// allows "if (dg==0) ..." to compile.
+
+//N=0
+template<class RetType=detail::DefaultVoid>
+class FastDelegate0 {
+private:
+ typedef typename detail::DefaultVoidToVoid<RetType>::type DesiredRetType;
+ typedef DesiredRetType (*StaticFunctionPtr)();
+ typedef RetType (*UnvoidStaticFunctionPtr)();
+ typedef RetType (detail::GenericClass::*GenericMemFn)();
+ typedef detail::ClosurePtr<GenericMemFn, StaticFunctionPtr, UnvoidStaticFunctionPtr> ClosureType;
+ ClosureType m_Closure;
+public:
+ // Typedefs to aid generic programming
+ typedef FastDelegate0 type;
+
+ // Construction and comparison functions
+ FastDelegate0() { clear(); }
+ FastDelegate0(const FastDelegate0 &x) {
+ m_Closure.CopyFrom(this, x.m_Closure); }
+ void operator = (const FastDelegate0 &x) {
+ m_Closure.CopyFrom(this, x.m_Closure); }
+ bool operator ==(const FastDelegate0 &x) const {
+ return m_Closure.IsEqual(x.m_Closure); }
+ bool operator !=(const FastDelegate0 &x) const {
+ return !m_Closure.IsEqual(x.m_Closure); }
+ bool operator <(const FastDelegate0 &x) const {
+ return m_Closure.IsLess(x.m_Closure); }
+ bool operator >(const FastDelegate0 &x) const {
+ return x.m_Closure.IsLess(m_Closure); }
+ // Binding to non-const member functions
+ template < class X, class Y >
+ FastDelegate0(Y *pthis, DesiredRetType (X::* function_to_bind)() ) {
+ m_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind); }
+ template < class X, class Y >
+ inline void bind(Y *pthis, DesiredRetType (X::* function_to_bind)()) {
+ m_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind); }
+ // Binding to const member functions.
+ template < class X, class Y >
+ FastDelegate0(const Y *pthis, DesiredRetType (X::* function_to_bind)() const) {
+ m_Closure.bindconstmemfunc(detail::implicit_cast<const X*>(pthis), function_to_bind); }
+ template < class X, class Y >
+ inline void bind(const Y *pthis, DesiredRetType (X::* function_to_bind)() const) {
+ m_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis), function_to_bind); }
+ // Static functions. We convert them into a member function call.
+ // This constructor also provides implicit conversion
+ FastDelegate0(DesiredRetType (*function_to_bind)() ) {
+ bind(function_to_bind); }
+ // for efficiency, prevent creation of a temporary
+ void operator = (DesiredRetType (*function_to_bind)() ) {
+ bind(function_to_bind); }
+ inline void bind(DesiredRetType (*function_to_bind)()) {
+ m_Closure.bindstaticfunc(this, &FastDelegate0::InvokeStaticFunction,
+ function_to_bind); }
+ // Invoke the delegate
+ RetType operator() () const {
+ return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(); }
+ // Implicit conversion to "bool" using the safe_bool idiom
+private:
+ typedef struct SafeBoolStruct {
+ int a_data_pointer_to_this_is_0_on_buggy_compilers;
+ StaticFunctionPtr m_nonzero;
+ } UselessTypedef;
+ typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type;
+public:
+ operator unspecified_bool_type() const {
+ return empty()? 0: &SafeBoolStruct::m_nonzero;
+ }
+ // necessary to allow ==0 to work despite the safe_bool idiom
+ inline bool operator==(StaticFunctionPtr funcptr) {
+ return m_Closure.IsEqualToStaticFuncPtr(funcptr); }
+ inline bool operator!=(StaticFunctionPtr funcptr) {
+ return !m_Closure.IsEqualToStaticFuncPtr(funcptr); }
+ inline bool operator ! () const { // Is it bound to anything?
+ return !m_Closure; }
+ inline bool empty() const {
+ return !m_Closure; }
+ void clear() { m_Closure.clear();}
+ // Conversion to and from the DelegateMemento storage class
+ const DelegateMemento & GetMemento() { return m_Closure; }
+ void SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); }
+
+private: // Invoker for static functions
+ RetType InvokeStaticFunction() const {
+ return (*(m_Closure.GetStaticFunction()))(); }
+};
+
+//N=1
+template<class Param1, class RetType=detail::DefaultVoid>
+class FastDelegate1 {
+private:
+ typedef typename detail::DefaultVoidToVoid<RetType>::type DesiredRetType;
+ typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1);
+ typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1);
+ typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1);
+ typedef detail::ClosurePtr<GenericMemFn, StaticFunctionPtr, UnvoidStaticFunctionPtr> ClosureType;
+ ClosureType m_Closure;
+public:
+ // Typedefs to aid generic programming
+ typedef FastDelegate1 type;
+
+ // Construction and comparison functions
+ FastDelegate1() { clear(); }
+ FastDelegate1(const FastDelegate1 &x) {
+ m_Closure.CopyFrom(this, x.m_Closure); }
+ void operator = (const FastDelegate1 &x) {
+ m_Closure.CopyFrom(this, x.m_Closure); }
+ bool operator ==(const FastDelegate1 &x) const {
+ return m_Closure.IsEqual(x.m_Closure); }
+ bool operator !=(const FastDelegate1 &x) const {
+ return !m_Closure.IsEqual(x.m_Closure); }
+ bool operator <(const FastDelegate1 &x) const {
+ return m_Closure.IsLess(x.m_Closure); }
+ bool operator >(const FastDelegate1 &x) const {
+ return x.m_Closure.IsLess(m_Closure); }
+ // Binding to non-const member functions
+ template < class X, class Y >
+ FastDelegate1(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1) ) {
+ m_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind); }
+ template < class X, class Y >
+ inline void bind(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1)) {
+ m_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind); }
+ // Binding to const member functions.
+ template < class X, class Y >
+ FastDelegate1(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1) const) {
+ m_Closure.bindconstmemfunc(detail::implicit_cast<const X*>(pthis), function_to_bind); }
+ template < class X, class Y >
+ inline void bind(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1) const) {
+ m_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis), function_to_bind); }
+ // Static functions. We convert them into a member function call.
+ // This constructor also provides implicit conversion
+ FastDelegate1(DesiredRetType (*function_to_bind)(Param1 p1) ) {
+ bind(function_to_bind); }
+ // for efficiency, prevent creation of a temporary
+ void operator = (DesiredRetType (*function_to_bind)(Param1 p1) ) {
+ bind(function_to_bind); }
+ inline void bind(DesiredRetType (*function_to_bind)(Param1 p1)) {
+ m_Closure.bindstaticfunc(this, &FastDelegate1::InvokeStaticFunction,
+ function_to_bind); }
+ // Invoke the delegate
+ RetType operator() (Param1 p1) const {
+ return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1); }
+ // Implicit conversion to "bool" using the safe_bool idiom
+private:
+ typedef struct SafeBoolStruct {
+ int a_data_pointer_to_this_is_0_on_buggy_compilers;
+ StaticFunctionPtr m_nonzero;
+ } UselessTypedef;
+ typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type;
+public:
+ operator unspecified_bool_type() const {
+ return empty()? 0: &SafeBoolStruct::m_nonzero;
+ }
+ // necessary to allow ==0 to work despite the safe_bool idiom
+ inline bool operator==(StaticFunctionPtr funcptr) {
+ return m_Closure.IsEqualToStaticFuncPtr(funcptr); }
+ inline bool operator!=(StaticFunctionPtr funcptr) {
+ return !m_Closure.IsEqualToStaticFuncPtr(funcptr); }
+ inline bool operator ! () const { // Is it bound to anything?
+ return !m_Closure; }
+ inline bool empty() const {
+ return !m_Closure; }
+ void clear() { m_Closure.clear();}
+ // Conversion to and from the DelegateMemento storage class
+ const DelegateMemento & GetMemento() { return m_Closure; }
+ void SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); }
+
+private: // Invoker for static functions
+ RetType InvokeStaticFunction(Param1 p1) const {
+ return (*(m_Closure.GetStaticFunction()))(p1); }
+};
+
+//N=2
+template<class Param1, class Param2, class RetType=detail::DefaultVoid>
+class FastDelegate2 {
+private:
+ typedef typename detail::DefaultVoidToVoid<RetType>::type DesiredRetType;
+ typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2);
+ typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2);
+ typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2);
+ typedef detail::ClosurePtr<GenericMemFn, StaticFunctionPtr, UnvoidStaticFunctionPtr> ClosureType;
+ ClosureType m_Closure;
+public:
+ // Typedefs to aid generic programming
+ typedef FastDelegate2 type;
+
+ // Construction and comparison functions
+ FastDelegate2() { clear(); }
+ FastDelegate2(const FastDelegate2 &x) {
+ m_Closure.CopyFrom(this, x.m_Closure); }
+ void operator = (const FastDelegate2 &x) {
+ m_Closure.CopyFrom(this, x.m_Closure); }
+ bool operator ==(const FastDelegate2 &x) const {
+ return m_Closure.IsEqual(x.m_Closure); }
+ bool operator !=(const FastDelegate2 &x) const {
+ return !m_Closure.IsEqual(x.m_Closure); }
+ bool operator <(const FastDelegate2 &x) const {
+ return m_Closure.IsLess(x.m_Closure); }
+ bool operator >(const FastDelegate2 &x) const {
+ return x.m_Closure.IsLess(m_Closure); }
+ // Binding to non-const member functions
+ template < class X, class Y >
+ FastDelegate2(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2) ) {
+ m_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind); }
+ template < class X, class Y >
+ inline void bind(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2)) {
+ m_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind); }
+ // Binding to const member functions.
+ template < class X, class Y >
+ FastDelegate2(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2) const) {
+ m_Closure.bindconstmemfunc(detail::implicit_cast<const X*>(pthis), function_to_bind); }
+ template < class X, class Y >
+ inline void bind(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2) const) {
+ m_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis), function_to_bind); }
+ // Static functions. We convert them into a member function call.
+ // This constructor also provides implicit conversion
+ FastDelegate2(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2) ) {
+ bind(function_to_bind); }
+ // for efficiency, prevent creation of a temporary
+ void operator = (DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2) ) {
+ bind(function_to_bind); }
+ inline void bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2)) {
+ m_Closure.bindstaticfunc(this, &FastDelegate2::InvokeStaticFunction,
+ function_to_bind); }
+ // Invoke the delegate
+ RetType operator() (Param1 p1, Param2 p2) const {
+ return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2); }
+ // Implicit conversion to "bool" using the safe_bool idiom
+private:
+ typedef struct SafeBoolStruct {
+ int a_data_pointer_to_this_is_0_on_buggy_compilers;
+ StaticFunctionPtr m_nonzero;
+ } UselessTypedef;
+ typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type;
+public:
+ operator unspecified_bool_type() const {
+ return empty()? 0: &SafeBoolStruct::m_nonzero;
+ }
+ // necessary to allow ==0 to work despite the safe_bool idiom
+ inline bool operator==(StaticFunctionPtr funcptr) {
+ return m_Closure.IsEqualToStaticFuncPtr(funcptr); }
+ inline bool operator!=(StaticFunctionPtr funcptr) {
+ return !m_Closure.IsEqualToStaticFuncPtr(funcptr); }
+ inline bool operator ! () const { // Is it bound to anything?
+ return !m_Closure; }
+ inline bool empty() const {
+ return !m_Closure; }
+ void clear() { m_Closure.clear();}
+ // Conversion to and from the DelegateMemento storage class
+ const DelegateMemento & GetMemento() { return m_Closure; }
+ void SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); }
+
+private: // Invoker for static functions
+ RetType InvokeStaticFunction(Param1 p1, Param2 p2) const {
+ return (*(m_Closure.GetStaticFunction()))(p1, p2); }
+};
+
+//N=3
+template<class Param1, class Param2, class Param3, class RetType=detail::DefaultVoid>
+class FastDelegate3 {
+private:
+ typedef typename detail::DefaultVoidToVoid<RetType>::type DesiredRetType;
+ typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3);
+ typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3);
+ typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2, Param3 p3);
+ typedef detail::ClosurePtr<GenericMemFn, StaticFunctionPtr, UnvoidStaticFunctionPtr> ClosureType;
+ ClosureType m_Closure;
+public:
+ // Typedefs to aid generic programming
+ typedef FastDelegate3 type;
+
+ // Construction and comparison functions
+ FastDelegate3() { clear(); }
+ FastDelegate3(const FastDelegate3 &x) {
+ m_Closure.CopyFrom(this, x.m_Closure); }
+ void operator = (const FastDelegate3 &x) {
+ m_Closure.CopyFrom(this, x.m_Closure); }
+ bool operator ==(const FastDelegate3 &x) const {
+ return m_Closure.IsEqual(x.m_Closure); }
+ bool operator !=(const FastDelegate3 &x) const {
+ return !m_Closure.IsEqual(x.m_Closure); }
+ bool operator <(const FastDelegate3 &x) const {
+ return m_Closure.IsLess(x.m_Closure); }
+ bool operator >(const FastDelegate3 &x) const {
+ return x.m_Closure.IsLess(m_Closure); }
+ // Binding to non-const member functions
+ template < class X, class Y >
+ FastDelegate3(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3) ) {
+ m_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind); }
+ template < class X, class Y >
+ inline void bind(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3)) {
+ m_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind); }
+ // Binding to const member functions.
+ template < class X, class Y >
+ FastDelegate3(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3) const) {
+ m_Closure.bindconstmemfunc(detail::implicit_cast<const X*>(pthis), function_to_bind); }
+ template < class X, class Y >
+ inline void bind(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3) const) {
+ m_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis), function_to_bind); }
+ // Static functions. We convert them into a member function call.
+ // This constructor also provides implicit conversion
+ FastDelegate3(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3) ) {
+ bind(function_to_bind); }
+ // for efficiency, prevent creation of a temporary
+ void operator = (DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3) ) {
+ bind(function_to_bind); }
+ inline void bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3)) {
+ m_Closure.bindstaticfunc(this, &FastDelegate3::InvokeStaticFunction,
+ function_to_bind); }
+ // Invoke the delegate
+ RetType operator() (Param1 p1, Param2 p2, Param3 p3) const {
+ return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2, p3); }
+ // Implicit conversion to "bool" using the safe_bool idiom
+private:
+ typedef struct SafeBoolStruct {
+ int a_data_pointer_to_this_is_0_on_buggy_compilers;
+ StaticFunctionPtr m_nonzero;
+ } UselessTypedef;
+ typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type;
+public:
+ operator unspecified_bool_type() const {
+ return empty()? 0: &SafeBoolStruct::m_nonzero;
+ }
+ // necessary to allow ==0 to work despite the safe_bool idiom
+ inline bool operator==(StaticFunctionPtr funcptr) {
+ return m_Closure.IsEqualToStaticFuncPtr(funcptr); }
+ inline bool operator!=(StaticFunctionPtr funcptr) {
+ return !m_Closure.IsEqualToStaticFuncPtr(funcptr); }
+ inline bool operator ! () const { // Is it bound to anything?
+ return !m_Closure; }
+ inline bool empty() const {
+ return !m_Closure; }
+ void clear() { m_Closure.clear();}
+ // Conversion to and from the DelegateMemento storage class
+ const DelegateMemento & GetMemento() { return m_Closure; }
+ void SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); }
+
+private: // Invoker for static functions
+ RetType InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3) const {
+ return (*(m_Closure.GetStaticFunction()))(p1, p2, p3); }
+};
+
+//N=4
+template<class Param1, class Param2, class Param3, class Param4, class RetType=detail::DefaultVoid>
+class FastDelegate4 {
+private:
+ typedef typename detail::DefaultVoidToVoid<RetType>::type DesiredRetType;
+ typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4);
+ typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4);
+ typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2, Param3 p3, Param4 p4);
+ typedef detail::ClosurePtr<GenericMemFn, StaticFunctionPtr, UnvoidStaticFunctionPtr> ClosureType;
+ ClosureType m_Closure;
+public:
+ // Typedefs to aid generic programming
+ typedef FastDelegate4 type;
+
+ // Construction and comparison functions
+ FastDelegate4() { clear(); }
+ FastDelegate4(const FastDelegate4 &x) {
+ m_Closure.CopyFrom(this, x.m_Closure); }
+ void operator = (const FastDelegate4 &x) {
+ m_Closure.CopyFrom(this, x.m_Closure); }
+ bool operator ==(const FastDelegate4 &x) const {
+ return m_Closure.IsEqual(x.m_Closure); }
+ bool operator !=(const FastDelegate4 &x) const {
+ return !m_Closure.IsEqual(x.m_Closure); }
+ bool operator <(const FastDelegate4 &x) const {
+ return m_Closure.IsLess(x.m_Closure); }
+ bool operator >(const FastDelegate4 &x) const {
+ return x.m_Closure.IsLess(m_Closure); }
+ // Binding to non-const member functions
+ template < class X, class Y >
+ FastDelegate4(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4) ) {
+ m_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind); }
+ template < class X, class Y >
+ inline void bind(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4)) {
+ m_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind); }
+ // Binding to const member functions.
+ template < class X, class Y >
+ FastDelegate4(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4) const) {
+ m_Closure.bindconstmemfunc(detail::implicit_cast<const X*>(pthis), function_to_bind); }
+ template < class X, class Y >
+ inline void bind(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4) const) {
+ m_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis), function_to_bind); }
+ // Static functions. We convert them into a member function call.
+ // This constructor also provides implicit conversion
+ FastDelegate4(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4) ) {
+ bind(function_to_bind); }
+ // for efficiency, prevent creation of a temporary
+ void operator = (DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4) ) {
+ bind(function_to_bind); }
+ inline void bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4)) {
+ m_Closure.bindstaticfunc(this, &FastDelegate4::InvokeStaticFunction,
+ function_to_bind); }
+ // Invoke the delegate
+ RetType operator() (Param1 p1, Param2 p2, Param3 p3, Param4 p4) const {
+ return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2, p3, p4); }
+ // Implicit conversion to "bool" using the safe_bool idiom
+private:
+ typedef struct SafeBoolStruct {
+ int a_data_pointer_to_this_is_0_on_buggy_compilers;
+ StaticFunctionPtr m_nonzero;
+ } UselessTypedef;
+ typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type;
+public:
+ operator unspecified_bool_type() const {
+ return empty()? 0: &SafeBoolStruct::m_nonzero;
+ }
+ // necessary to allow ==0 to work despite the safe_bool idiom
+ inline bool operator==(StaticFunctionPtr funcptr) {
+ return m_Closure.IsEqualToStaticFuncPtr(funcptr); }
+ inline bool operator!=(StaticFunctionPtr funcptr) {
+ return !m_Closure.IsEqualToStaticFuncPtr(funcptr); }
+ inline bool operator ! () const { // Is it bound to anything?
+ return !m_Closure; }
+ inline bool empty() const {
+ return !m_Closure; }
+ void clear() { m_Closure.clear();}
+ // Conversion to and from the DelegateMemento storage class
+ const DelegateMemento & GetMemento() { return m_Closure; }
+ void SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); }
+
+private: // Invoker for static functions
+ RetType InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3, Param4 p4) const {
+ return (*(m_Closure.GetStaticFunction()))(p1, p2, p3, p4); }
+};
+
+//N=5
+template<class Param1, class Param2, class Param3, class Param4, class Param5, class RetType=detail::DefaultVoid>
+class FastDelegate5 {
+private:
+ typedef typename detail::DefaultVoidToVoid<RetType>::type DesiredRetType;
+ typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5);
+ typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5);
+ typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5);
+ typedef detail::ClosurePtr<GenericMemFn, StaticFunctionPtr, UnvoidStaticFunctionPtr> ClosureType;
+ ClosureType m_Closure;
+public:
+ // Typedefs to aid generic programming
+ typedef FastDelegate5 type;
+
+ // Construction and comparison functions
+ FastDelegate5() { clear(); }
+ FastDelegate5(const FastDelegate5 &x) {
+ m_Closure.CopyFrom(this, x.m_Closure); }
+ void operator = (const FastDelegate5 &x) {
+ m_Closure.CopyFrom(this, x.m_Closure); }
+ bool operator ==(const FastDelegate5 &x) const {
+ return m_Closure.IsEqual(x.m_Closure); }
+ bool operator !=(const FastDelegate5 &x) const {
+ return !m_Closure.IsEqual(x.m_Closure); }
+ bool operator <(const FastDelegate5 &x) const {
+ return m_Closure.IsLess(x.m_Closure); }
+ bool operator >(const FastDelegate5 &x) const {
+ return x.m_Closure.IsLess(m_Closure); }
+ // Binding to non-const member functions
+ template < class X, class Y >
+ FastDelegate5(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) ) {
+ m_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind); }
+ template < class X, class Y >
+ inline void bind(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5)) {
+ m_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind); }
+ // Binding to const member functions.
+ template < class X, class Y >
+ FastDelegate5(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) const) {
+ m_Closure.bindconstmemfunc(detail::implicit_cast<const X*>(pthis), function_to_bind); }
+ template < class X, class Y >
+ inline void bind(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) const) {
+ m_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis), function_to_bind); }
+ // Static functions. We convert them into a member function call.
+ // This constructor also provides implicit conversion
+ FastDelegate5(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) ) {
+ bind(function_to_bind); }
+ // for efficiency, prevent creation of a temporary
+ void operator = (DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) ) {
+ bind(function_to_bind); }
+ inline void bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5)) {
+ m_Closure.bindstaticfunc(this, &FastDelegate5::InvokeStaticFunction,
+ function_to_bind); }
+ // Invoke the delegate
+ RetType operator() (Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) const {
+ return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2, p3, p4, p5); }
+ // Implicit conversion to "bool" using the safe_bool idiom
+private:
+ typedef struct SafeBoolStruct {
+ int a_data_pointer_to_this_is_0_on_buggy_compilers;
+ StaticFunctionPtr m_nonzero;
+ } UselessTypedef;
+ typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type;
+public:
+ operator unspecified_bool_type() const {
+ return empty()? 0: &SafeBoolStruct::m_nonzero;
+ }
+ // necessary to allow ==0 to work despite the safe_bool idiom
+ inline bool operator==(StaticFunctionPtr funcptr) {
+ return m_Closure.IsEqualToStaticFuncPtr(funcptr); }
+ inline bool operator!=(StaticFunctionPtr funcptr) {
+ return !m_Closure.IsEqualToStaticFuncPtr(funcptr); }
+ inline bool operator ! () const { // Is it bound to anything?
+ return !m_Closure; }
+ inline bool empty() const {
+ return !m_Closure; }
+ void clear() { m_Closure.clear();}
+ // Conversion to and from the DelegateMemento storage class
+ const DelegateMemento & GetMemento() { return m_Closure; }
+ void SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); }
+
+private: // Invoker for static functions
+ RetType InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) const {
+ return (*(m_Closure.GetStaticFunction()))(p1, p2, p3, p4, p5); }
+};
+
+//N=6
+template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class RetType=detail::DefaultVoid>
+class FastDelegate6 {
+private:
+ typedef typename detail::DefaultVoidToVoid<RetType>::type DesiredRetType;
+ typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6);
+ typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6);
+ typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6);
+ typedef detail::ClosurePtr<GenericMemFn, StaticFunctionPtr, UnvoidStaticFunctionPtr> ClosureType;
+ ClosureType m_Closure;
+public:
+ // Typedefs to aid generic programming
+ typedef FastDelegate6 type;
+
+ // Construction and comparison functions
+ FastDelegate6() { clear(); }
+ FastDelegate6(const FastDelegate6 &x) {
+ m_Closure.CopyFrom(this, x.m_Closure); }
+ void operator = (const FastDelegate6 &x) {
+ m_Closure.CopyFrom(this, x.m_Closure); }
+ bool operator ==(const FastDelegate6 &x) const {
+ return m_Closure.IsEqual(x.m_Closure); }
+ bool operator !=(const FastDelegate6 &x) const {
+ return !m_Closure.IsEqual(x.m_Closure); }
+ bool operator <(const FastDelegate6 &x) const {
+ return m_Closure.IsLess(x.m_Closure); }
+ bool operator >(const FastDelegate6 &x) const {
+ return x.m_Closure.IsLess(m_Closure); }
+ // Binding to non-const member functions
+ template < class X, class Y >
+ FastDelegate6(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) ) {
+ m_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind); }
+ template < class X, class Y >
+ inline void bind(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6)) {
+ m_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind); }
+ // Binding to const member functions.
+ template < class X, class Y >
+ FastDelegate6(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) const) {
+ m_Closure.bindconstmemfunc(detail::implicit_cast<const X*>(pthis), function_to_bind); }
+ template < class X, class Y >
+ inline void bind(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) const) {
+ m_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis), function_to_bind); }
+ // Static functions. We convert them into a member function call.
+ // This constructor also provides implicit conversion
+ FastDelegate6(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) ) {
+ bind(function_to_bind); }
+ // for efficiency, prevent creation of a temporary
+ void operator = (DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) ) {
+ bind(function_to_bind); }
+ inline void bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6)) {
+ m_Closure.bindstaticfunc(this, &FastDelegate6::InvokeStaticFunction,
+ function_to_bind); }
+ // Invoke the delegate
+ RetType operator() (Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) const {
+ return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2, p3, p4, p5, p6); }
+ // Implicit conversion to "bool" using the safe_bool idiom
+private:
+ typedef struct SafeBoolStruct {
+ int a_data_pointer_to_this_is_0_on_buggy_compilers;
+ StaticFunctionPtr m_nonzero;
+ } UselessTypedef;
+ typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type;
+public:
+ operator unspecified_bool_type() const {
+ return empty()? 0: &SafeBoolStruct::m_nonzero;
+ }
+ // necessary to allow ==0 to work despite the safe_bool idiom
+ inline bool operator==(StaticFunctionPtr funcptr) {
+ return m_Closure.IsEqualToStaticFuncPtr(funcptr); }
+ inline bool operator!=(StaticFunctionPtr funcptr) {
+ return !m_Closure.IsEqualToStaticFuncPtr(funcptr); }
+ inline bool operator ! () const { // Is it bound to anything?
+ return !m_Closure; }
+ inline bool empty() const {
+ return !m_Closure; }
+ void clear() { m_Closure.clear();}
+ // Conversion to and from the DelegateMemento storage class
+ const DelegateMemento & GetMemento() { return m_Closure; }
+ void SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); }
+
+private: // Invoker for static functions
+ RetType InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) const {
+ return (*(m_Closure.GetStaticFunction()))(p1, p2, p3, p4, p5, p6); }
+};
+
+//N=7
+template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class RetType=detail::DefaultVoid>
+class FastDelegate7 {
+private:
+ typedef typename detail::DefaultVoidToVoid<RetType>::type DesiredRetType;
+ typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7);
+ typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7);
+ typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7);
+ typedef detail::ClosurePtr<GenericMemFn, StaticFunctionPtr, UnvoidStaticFunctionPtr> ClosureType;
+ ClosureType m_Closure;
+public:
+ // Typedefs to aid generic programming
+ typedef FastDelegate7 type;
+
+ // Construction and comparison functions
+ FastDelegate7() { clear(); }
+ FastDelegate7(const FastDelegate7 &x) {
+ m_Closure.CopyFrom(this, x.m_Closure); }
+ void operator = (const FastDelegate7 &x) {
+ m_Closure.CopyFrom(this, x.m_Closure); }
+ bool operator ==(const FastDelegate7 &x) const {
+ return m_Closure.IsEqual(x.m_Closure); }
+ bool operator !=(const FastDelegate7 &x) const {
+ return !m_Closure.IsEqual(x.m_Closure); }
+ bool operator <(const FastDelegate7 &x) const {
+ return m_Closure.IsLess(x.m_Closure); }
+ bool operator >(const FastDelegate7 &x) const {
+ return x.m_Closure.IsLess(m_Closure); }
+ // Binding to non-const member functions
+ template < class X, class Y >
+ FastDelegate7(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) ) {
+ m_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind); }
+ template < class X, class Y >
+ inline void bind(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7)) {
+ m_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind); }
+ // Binding to const member functions.
+ template < class X, class Y >
+ FastDelegate7(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) const) {
+ m_Closure.bindconstmemfunc(detail::implicit_cast<const X*>(pthis), function_to_bind); }
+ template < class X, class Y >
+ inline void bind(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) const) {
+ m_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis), function_to_bind); }
+ // Static functions. We convert them into a member function call.
+ // This constructor also provides implicit conversion
+ FastDelegate7(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) ) {
+ bind(function_to_bind); }
+ // for efficiency, prevent creation of a temporary
+ void operator = (DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) ) {
+ bind(function_to_bind); }
+ inline void bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7)) {
+ m_Closure.bindstaticfunc(this, &FastDelegate7::InvokeStaticFunction,
+ function_to_bind); }
+ // Invoke the delegate
+ RetType operator() (Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) const {
+ return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2, p3, p4, p5, p6, p7); }
+ // Implicit conversion to "bool" using the safe_bool idiom
+private:
+ typedef struct SafeBoolStruct {
+ int a_data_pointer_to_this_is_0_on_buggy_compilers;
+ StaticFunctionPtr m_nonzero;
+ } UselessTypedef;
+ typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type;
+public:
+ operator unspecified_bool_type() const {
+ return empty()? 0: &SafeBoolStruct::m_nonzero;
+ }
+ // necessary to allow ==0 to work despite the safe_bool idiom
+ inline bool operator==(StaticFunctionPtr funcptr) {
+ return m_Closure.IsEqualToStaticFuncPtr(funcptr); }
+ inline bool operator!=(StaticFunctionPtr funcptr) {
+ return !m_Closure.IsEqualToStaticFuncPtr(funcptr); }
+ inline bool operator ! () const { // Is it bound to anything?
+ return !m_Closure; }
+ inline bool empty() const {
+ return !m_Closure; }
+ void clear() { m_Closure.clear();}
+ // Conversion to and from the DelegateMemento storage class
+ const DelegateMemento & GetMemento() { return m_Closure; }
+ void SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); }
+
+private: // Invoker for static functions
+ RetType InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) const {
+ return (*(m_Closure.GetStaticFunction()))(p1, p2, p3, p4, p5, p6, p7); }
+};
+
+//N=8
+template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class RetType=detail::DefaultVoid>
+class FastDelegate8 {
+private:
+ typedef typename detail::DefaultVoidToVoid<RetType>::type DesiredRetType;
+ typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8);
+ typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8);
+ typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8);
+ typedef detail::ClosurePtr<GenericMemFn, StaticFunctionPtr, UnvoidStaticFunctionPtr> ClosureType;
+ ClosureType m_Closure;
+public:
+ // Typedefs to aid generic programming
+ typedef FastDelegate8 type;
+
+ // Construction and comparison functions
+ FastDelegate8() { clear(); }
+ FastDelegate8(const FastDelegate8 &x) {
+ m_Closure.CopyFrom(this, x.m_Closure); }
+ void operator = (const FastDelegate8 &x) {
+ m_Closure.CopyFrom(this, x.m_Closure); }
+ bool operator ==(const FastDelegate8 &x) const {
+ return m_Closure.IsEqual(x.m_Closure); }
+ bool operator !=(const FastDelegate8 &x) const {
+ return !m_Closure.IsEqual(x.m_Closure); }
+ bool operator <(const FastDelegate8 &x) const {
+ return m_Closure.IsLess(x.m_Closure); }
+ bool operator >(const FastDelegate8 &x) const {
+ return x.m_Closure.IsLess(m_Closure); }
+ // Binding to non-const member functions
+ template < class X, class Y >
+ FastDelegate8(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) ) {
+ m_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind); }
+ template < class X, class Y >
+ inline void bind(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8)) {
+ m_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind); }
+ // Binding to const member functions.
+ template < class X, class Y >
+ FastDelegate8(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) const) {
+ m_Closure.bindconstmemfunc(detail::implicit_cast<const X*>(pthis), function_to_bind); }
+ template < class X, class Y >
+ inline void bind(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) const) {
+ m_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis), function_to_bind); }
+ // Static functions. We convert them into a member function call.
+ // This constructor also provides implicit conversion
+ FastDelegate8(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) ) {
+ bind(function_to_bind); }
+ // for efficiency, prevent creation of a temporary
+ void operator = (DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) ) {
+ bind(function_to_bind); }
+ inline void bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8)) {
+ m_Closure.bindstaticfunc(this, &FastDelegate8::InvokeStaticFunction,
+ function_to_bind); }
+ // Invoke the delegate
+ RetType operator() (Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) const {
+ return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2, p3, p4, p5, p6, p7, p8); }
+ // Implicit conversion to "bool" using the safe_bool idiom
+private:
+ typedef struct SafeBoolStruct {
+ int a_data_pointer_to_this_is_0_on_buggy_compilers;
+ StaticFunctionPtr m_nonzero;
+ } UselessTypedef;
+ typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type;
+public:
+ operator unspecified_bool_type() const {
+ return empty()? 0: &SafeBoolStruct::m_nonzero;
+ }
+ // necessary to allow ==0 to work despite the safe_bool idiom
+ inline bool operator==(StaticFunctionPtr funcptr) {
+ return m_Closure.IsEqualToStaticFuncPtr(funcptr); }
+ inline bool operator!=(StaticFunctionPtr funcptr) {
+ return !m_Closure.IsEqualToStaticFuncPtr(funcptr); }
+ inline bool operator ! () const { // Is it bound to anything?
+ return !m_Closure; }
+ inline bool empty() const {
+ return !m_Closure; }
+ void clear() { m_Closure.clear();}
+ // Conversion to and from the DelegateMemento storage class
+ const DelegateMemento & GetMemento() { return m_Closure; }
+ void SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); }
+
+private: // Invoker for static functions
+ RetType InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) const {
+ return (*(m_Closure.GetStaticFunction()))(p1, p2, p3, p4, p5, p6, p7, p8); }
+};
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Fast Delegates, part 4:
+//
+// FastDelegate<> class (Original author: Jody Hagins)
+// Allows boost::function style syntax like:
+// FastDelegate< double (int, long) >
+// instead of:
+// FastDelegate2< int, long, double >
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#ifdef FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX
+
+// Declare FastDelegate as a class template. It will be specialized
+// later for all number of arguments.
+template <typename Signature>
+class FastDelegate;
+
+//N=0
+// Specialization to allow use of
+// FastDelegate< R ( ) >
+// instead of
+// FastDelegate0 < R >
+template<typename R>
+class FastDelegate< R ( ) >
+ // Inherit from FastDelegate0 so that it can be treated just like a FastDelegate0
+ : public FastDelegate0 < R >
+{
+public:
+ // Make using the base type a bit easier via typedef.
+ typedef FastDelegate0 < R > BaseType;
+
+ // Allow users access to the specific type of this delegate.
+ typedef FastDelegate SelfType;
+
+ // Mimic the base class constructors.
+ FastDelegate() : BaseType() { }
+
+ template < class X, class Y >
+ FastDelegate(Y * pthis,
+ R (X::* function_to_bind)( ))
+ : BaseType(pthis, function_to_bind) { }
+
+ template < class X, class Y >
+ FastDelegate(const Y *pthis,
+ R (X::* function_to_bind)( ) const)
+ : BaseType(pthis, function_to_bind)
+ { }
+
+ FastDelegate(R (*function_to_bind)( ))
+ : BaseType(function_to_bind) { }
+ void operator = (const BaseType &x) {
+ *static_cast<BaseType*>(this) = x; }
+};
+
+//N=1
+// Specialization to allow use of
+// FastDelegate< R ( Param1 ) >
+// instead of
+// FastDelegate1 < Param1, R >
+template<typename R, class Param1>
+class FastDelegate< R ( Param1 ) >
+ // Inherit from FastDelegate1 so that it can be treated just like a FastDelegate1
+ : public FastDelegate1 < Param1, R >
+{
+public:
+ // Make using the base type a bit easier via typedef.
+ typedef FastDelegate1 < Param1, R > BaseType;
+
+ // Allow users access to the specific type of this delegate.
+ typedef FastDelegate SelfType;
+
+ // Mimic the base class constructors.
+ FastDelegate() : BaseType() { }
+
+ template < class X, class Y >
+ FastDelegate(Y * pthis,
+ R (X::* function_to_bind)( Param1 p1 ))
+ : BaseType(pthis, function_to_bind) { }
+
+ template < class X, class Y >
+ FastDelegate(const Y *pthis,
+ R (X::* function_to_bind)( Param1 p1 ) const)
+ : BaseType(pthis, function_to_bind)
+ { }
+
+ FastDelegate(R (*function_to_bind)( Param1 p1 ))
+ : BaseType(function_to_bind) { }
+ void operator = (const BaseType &x) {
+ *static_cast<BaseType*>(this) = x; }
+};
+
+//N=2
+// Specialization to allow use of
+// FastDelegate< R ( Param1, Param2 ) >
+// instead of
+// FastDelegate2 < Param1, Param2, R >
+template<typename R, class Param1, class Param2>
+class FastDelegate< R ( Param1, Param2 ) >
+ // Inherit from FastDelegate2 so that it can be treated just like a FastDelegate2
+ : public FastDelegate2 < Param1, Param2, R >
+{
+public:
+ // Make using the base type a bit easier via typedef.
+ typedef FastDelegate2 < Param1, Param2, R > BaseType;
+
+ // Allow users access to the specific type of this delegate.
+ typedef FastDelegate SelfType;
+
+ // Mimic the base class constructors.
+ FastDelegate() : BaseType() { }
+
+ template < class X, class Y >
+ FastDelegate(Y * pthis,
+ R (X::* function_to_bind)( Param1 p1, Param2 p2 ))
+ : BaseType(pthis, function_to_bind) { }
+
+ template < class X, class Y >
+ FastDelegate(const Y *pthis,
+ R (X::* function_to_bind)( Param1 p1, Param2 p2 ) const)
+ : BaseType(pthis, function_to_bind)
+ { }
+
+ FastDelegate(R (*function_to_bind)( Param1 p1, Param2 p2 ))
+ : BaseType(function_to_bind) { }
+ void operator = (const BaseType &x) {
+ *static_cast<BaseType*>(this) = x; }
+};
+
+//N=3
+// Specialization to allow use of
+// FastDelegate< R ( Param1, Param2, Param3 ) >
+// instead of
+// FastDelegate3 < Param1, Param2, Param3, R >
+template<typename R, class Param1, class Param2, class Param3>
+class FastDelegate< R ( Param1, Param2, Param3 ) >
+ // Inherit from FastDelegate3 so that it can be treated just like a FastDelegate3
+ : public FastDelegate3 < Param1, Param2, Param3, R >
+{
+public:
+ // Make using the base type a bit easier via typedef.
+ typedef FastDelegate3 < Param1, Param2, Param3, R > BaseType;
+
+ // Allow users access to the specific type of this delegate.
+ typedef FastDelegate SelfType;
+
+ // Mimic the base class constructors.
+ FastDelegate() : BaseType() { }
+
+ template < class X, class Y >
+ FastDelegate(Y * pthis,
+ R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3 ))
+ : BaseType(pthis, function_to_bind) { }
+
+ template < class X, class Y >
+ FastDelegate(const Y *pthis,
+ R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3 ) const)
+ : BaseType(pthis, function_to_bind)
+ { }
+
+ FastDelegate(R (*function_to_bind)( Param1 p1, Param2 p2, Param3 p3 ))
+ : BaseType(function_to_bind) { }
+ void operator = (const BaseType &x) {
+ *static_cast<BaseType*>(this) = x; }
+};
+
+//N=4
+// Specialization to allow use of
+// FastDelegate< R ( Param1, Param2, Param3, Param4 ) >
+// instead of
+// FastDelegate4 < Param1, Param2, Param3, Param4, R >
+template<typename R, class Param1, class Param2, class Param3, class Param4>
+class FastDelegate< R ( Param1, Param2, Param3, Param4 ) >
+ // Inherit from FastDelegate4 so that it can be treated just like a FastDelegate4
+ : public FastDelegate4 < Param1, Param2, Param3, Param4, R >
+{
+public:
+ // Make using the base type a bit easier via typedef.
+ typedef FastDelegate4 < Param1, Param2, Param3, Param4, R > BaseType;
+
+ // Allow users access to the specific type of this delegate.
+ typedef FastDelegate SelfType;
+
+ // Mimic the base class constructors.
+ FastDelegate() : BaseType() { }
+
+ template < class X, class Y >
+ FastDelegate(Y * pthis,
+ R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4 ))
+ : BaseType(pthis, function_to_bind) { }
+
+ template < class X, class Y >
+ FastDelegate(const Y *pthis,
+ R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4 ) const)
+ : BaseType(pthis, function_to_bind)
+ { }
+
+ FastDelegate(R (*function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4 ))
+ : BaseType(function_to_bind) { }
+ void operator = (const BaseType &x) {
+ *static_cast<BaseType*>(this) = x; }
+};
+
+//N=5
+// Specialization to allow use of
+// FastDelegate< R ( Param1, Param2, Param3, Param4, Param5 ) >
+// instead of
+// FastDelegate5 < Param1, Param2, Param3, Param4, Param5, R >
+template<typename R, class Param1, class Param2, class Param3, class Param4, class Param5>
+class FastDelegate< R ( Param1, Param2, Param3, Param4, Param5 ) >
+ // Inherit from FastDelegate5 so that it can be treated just like a FastDelegate5
+ : public FastDelegate5 < Param1, Param2, Param3, Param4, Param5, R >
+{
+public:
+ // Make using the base type a bit easier via typedef.
+ typedef FastDelegate5 < Param1, Param2, Param3, Param4, Param5, R > BaseType;
+
+ // Allow users access to the specific type of this delegate.
+ typedef FastDelegate SelfType;
+
+ // Mimic the base class constructors.
+ FastDelegate() : BaseType() { }
+
+ template < class X, class Y >
+ FastDelegate(Y * pthis,
+ R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5 ))
+ : BaseType(pthis, function_to_bind) { }
+
+ template < class X, class Y >
+ FastDelegate(const Y *pthis,
+ R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5 ) const)
+ : BaseType(pthis, function_to_bind)
+ { }
+
+ FastDelegate(R (*function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5 ))
+ : BaseType(function_to_bind) { }
+ void operator = (const BaseType &x) {
+ *static_cast<BaseType*>(this) = x; }
+};
+
+//N=6
+// Specialization to allow use of
+// FastDelegate< R ( Param1, Param2, Param3, Param4, Param5, Param6 ) >
+// instead of
+// FastDelegate6 < Param1, Param2, Param3, Param4, Param5, Param6, R >
+template<typename R, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6>
+class FastDelegate< R ( Param1, Param2, Param3, Param4, Param5, Param6 ) >
+ // Inherit from FastDelegate6 so that it can be treated just like a FastDelegate6
+ : public FastDelegate6 < Param1, Param2, Param3, Param4, Param5, Param6, R >
+{
+public:
+ // Make using the base type a bit easier via typedef.
+ typedef FastDelegate6 < Param1, Param2, Param3, Param4, Param5, Param6, R > BaseType;
+
+ // Allow users access to the specific type of this delegate.
+ typedef FastDelegate SelfType;
+
+ // Mimic the base class constructors.
+ FastDelegate() : BaseType() { }
+
+ template < class X, class Y >
+ FastDelegate(Y * pthis,
+ R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6 ))
+ : BaseType(pthis, function_to_bind) { }
+
+ template < class X, class Y >
+ FastDelegate(const Y *pthis,
+ R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6 ) const)
+ : BaseType(pthis, function_to_bind)
+ { }
+
+ FastDelegate(R (*function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6 ))
+ : BaseType(function_to_bind) { }
+ void operator = (const BaseType &x) {
+ *static_cast<BaseType*>(this) = x; }
+};
+
+//N=7
+// Specialization to allow use of
+// FastDelegate< R ( Param1, Param2, Param3, Param4, Param5, Param6, Param7 ) >
+// instead of
+// FastDelegate7 < Param1, Param2, Param3, Param4, Param5, Param6, Param7, R >
+template<typename R, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7>
+class FastDelegate< R ( Param1, Param2, Param3, Param4, Param5, Param6, Param7 ) >
+ // Inherit from FastDelegate7 so that it can be treated just like a FastDelegate7
+ : public FastDelegate7 < Param1, Param2, Param3, Param4, Param5, Param6, Param7, R >
+{
+public:
+ // Make using the base type a bit easier via typedef.
+ typedef FastDelegate7 < Param1, Param2, Param3, Param4, Param5, Param6, Param7, R > BaseType;
+
+ // Allow users access to the specific type of this delegate.
+ typedef FastDelegate SelfType;
+
+ // Mimic the base class constructors.
+ FastDelegate() : BaseType() { }
+
+ template < class X, class Y >
+ FastDelegate(Y * pthis,
+ R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7 ))
+ : BaseType(pthis, function_to_bind) { }
+
+ template < class X, class Y >
+ FastDelegate(const Y *pthis,
+ R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7 ) const)
+ : BaseType(pthis, function_to_bind)
+ { }
+
+ FastDelegate(R (*function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7 ))
+ : BaseType(function_to_bind) { }
+ void operator = (const BaseType &x) {
+ *static_cast<BaseType*>(this) = x; }
+};
+
+//N=8
+// Specialization to allow use of
+// FastDelegate< R ( Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8 ) >
+// instead of
+// FastDelegate8 < Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, R >
+template<typename R, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8>
+class FastDelegate< R ( Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8 ) >
+ // Inherit from FastDelegate8 so that it can be treated just like a FastDelegate8
+ : public FastDelegate8 < Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, R >
+{
+public:
+ // Make using the base type a bit easier via typedef.
+ typedef FastDelegate8 < Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, R > BaseType;
+
+ // Allow users access to the specific type of this delegate.
+ typedef FastDelegate SelfType;
+
+ // Mimic the base class constructors.
+ FastDelegate() : BaseType() { }
+
+ template < class X, class Y >
+ FastDelegate(Y * pthis,
+ R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8 ))
+ : BaseType(pthis, function_to_bind) { }
+
+ template < class X, class Y >
+ FastDelegate(const Y *pthis,
+ R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8 ) const)
+ : BaseType(pthis, function_to_bind)
+ { }
+
+ FastDelegate(R (*function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8 ))
+ : BaseType(function_to_bind) { }
+ void operator = (const BaseType &x) {
+ *static_cast<BaseType*>(this) = x; }
+};
+
+
+#endif //FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX
+
+////////////////////////////////////////////////////////////////////////////////
+// Fast Delegates, part 5:
+//
+// MakeDelegate() helper function
+//
+// MakeDelegate(&x, &X::func) returns a fastdelegate of the type
+// necessary for calling x.func() with the correct number of arguments.
+// This makes it possible to eliminate many typedefs from user code.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// Also declare overloads of a MakeDelegate() global function to
+// reduce the need for typedefs.
+// We need seperate overloads for const and non-const member functions.
+// Also, because of the weird rule about the class of derived member function pointers,
+// implicit downcasts may need to be applied later to the 'this' pointer.
+// That's why two classes (X and Y) appear in the definitions. Y must be implicitly
+// castable to X.
+
+// Workaround for VC6. VC6 needs void return types converted into DefaultVoid.
+// GCC 3.2 and later won't compile this unless it's preceded by 'typename',
+// but VC6 doesn't allow 'typename' in this context.
+// So, I have to use a macro.
+
+#ifdef FASTDLGT_VC6
+#define FASTDLGT_RETTYPE detail::VoidToDefaultVoid<RetType>::type
+#else
+#define FASTDLGT_RETTYPE RetType
+#endif
+
+//N=0
+template <class X, class Y, class RetType>
+FastDelegate0<FASTDLGT_RETTYPE> MakeDelegate(Y* x, RetType (X::*func)()) {
+ return FastDelegate0<FASTDLGT_RETTYPE>(x, func);
+}
+
+template <class X, class Y, class RetType>
+FastDelegate0<FASTDLGT_RETTYPE> MakeDelegate(Y* x, RetType (X::*func)() const) {
+ return FastDelegate0<FASTDLGT_RETTYPE>(x, func);
+}
+
+//N=1
+template <class X, class Y, class Param1, class RetType>
+FastDelegate1<Param1, FASTDLGT_RETTYPE> MakeDelegate(Y* x, RetType (X::*func)(Param1 p1)) {
+ return FastDelegate1<Param1, FASTDLGT_RETTYPE>(x, func);
+}
+
+template <class X, class Y, class Param1, class RetType>
+FastDelegate1<Param1, FASTDLGT_RETTYPE> MakeDelegate(Y* x, RetType (X::*func)(Param1 p1) const) {
+ return FastDelegate1<Param1, FASTDLGT_RETTYPE>(x, func);
+}
+
+//N=2
+template <class X, class Y, class Param1, class Param2, class RetType>
+FastDelegate2<Param1, Param2, FASTDLGT_RETTYPE> MakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2)) {
+ return FastDelegate2<Param1, Param2, FASTDLGT_RETTYPE>(x, func);
+}
+
+template <class X, class Y, class Param1, class Param2, class RetType>
+FastDelegate2<Param1, Param2, FASTDLGT_RETTYPE> MakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2) const) {
+ return FastDelegate2<Param1, Param2, FASTDLGT_RETTYPE>(x, func);
+}
+
+//N=3
+template <class X, class Y, class Param1, class Param2, class Param3, class RetType>
+FastDelegate3<Param1, Param2, Param3, FASTDLGT_RETTYPE> MakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3)) {
+ return FastDelegate3<Param1, Param2, Param3, FASTDLGT_RETTYPE>(x, func);
+}
+
+template <class X, class Y, class Param1, class Param2, class Param3, class RetType>
+FastDelegate3<Param1, Param2, Param3, FASTDLGT_RETTYPE> MakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3) const) {
+ return FastDelegate3<Param1, Param2, Param3, FASTDLGT_RETTYPE>(x, func);
+}
+
+//N=4
+template <class X, class Y, class Param1, class Param2, class Param3, class Param4, class RetType>
+FastDelegate4<Param1, Param2, Param3, Param4, FASTDLGT_RETTYPE> MakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4)) {
+ return FastDelegate4<Param1, Param2, Param3, Param4, FASTDLGT_RETTYPE>(x, func);
+}
+
+template <class X, class Y, class Param1, class Param2, class Param3, class Param4, class RetType>
+FastDelegate4<Param1, Param2, Param3, Param4, FASTDLGT_RETTYPE> MakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4) const) {
+ return FastDelegate4<Param1, Param2, Param3, Param4, FASTDLGT_RETTYPE>(x, func);
+}
+
+//N=5
+template <class X, class Y, class Param1, class Param2, class Param3, class Param4, class Param5, class RetType>
+FastDelegate5<Param1, Param2, Param3, Param4, Param5, FASTDLGT_RETTYPE> MakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5)) {
+ return FastDelegate5<Param1, Param2, Param3, Param4, Param5, FASTDLGT_RETTYPE>(x, func);
+}
+
+template <class X, class Y, class Param1, class Param2, class Param3, class Param4, class Param5, class RetType>
+FastDelegate5<Param1, Param2, Param3, Param4, Param5, FASTDLGT_RETTYPE> MakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) const) {
+ return FastDelegate5<Param1, Param2, Param3, Param4, Param5, FASTDLGT_RETTYPE>(x, func);
+}
+
+//N=6
+template <class X, class Y, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class RetType>
+FastDelegate6<Param1, Param2, Param3, Param4, Param5, Param6, FASTDLGT_RETTYPE> MakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6)) {
+ return FastDelegate6<Param1, Param2, Param3, Param4, Param5, Param6, FASTDLGT_RETTYPE>(x, func);
+}
+
+template <class X, class Y, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class RetType>
+FastDelegate6<Param1, Param2, Param3, Param4, Param5, Param6, FASTDLGT_RETTYPE> MakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) const) {
+ return FastDelegate6<Param1, Param2, Param3, Param4, Param5, Param6, FASTDLGT_RETTYPE>(x, func);
+}
+
+//N=7
+template <class X, class Y, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class RetType>
+FastDelegate7<Param1, Param2, Param3, Param4, Param5, Param6, Param7, FASTDLGT_RETTYPE> MakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7)) {
+ return FastDelegate7<Param1, Param2, Param3, Param4, Param5, Param6, Param7, FASTDLGT_RETTYPE>(x, func);
+}
+
+template <class X, class Y, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class RetType>
+FastDelegate7<Param1, Param2, Param3, Param4, Param5, Param6, Param7, FASTDLGT_RETTYPE> MakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) const) {
+ return FastDelegate7<Param1, Param2, Param3, Param4, Param5, Param6, Param7, FASTDLGT_RETTYPE>(x, func);
+}
+
+//N=8
+template <class X, class Y, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class RetType>
+FastDelegate8<Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, FASTDLGT_RETTYPE> MakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8)) {
+ return FastDelegate8<Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, FASTDLGT_RETTYPE>(x, func);
+}
+
+template <class X, class Y, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class RetType>
+FastDelegate8<Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, FASTDLGT_RETTYPE> MakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) const) {
+ return FastDelegate8<Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, FASTDLGT_RETTYPE>(x, func);
+}
+
+
+ // clean up after ourselves...
+#undef FASTDLGT_RETTYPE
+
+} // namespace fastdelegate
+
+#endif // !defined(FASTDELEGATE_H)
+
diff --git a/emb/pastilda/lib/fastdelegate/FastDelegateBind.h b/emb/pastilda/lib/fastdelegate/FastDelegateBind.h
new file mode 100644
index 0000000..9830ab5
--- /dev/null
+++ b/emb/pastilda/lib/fastdelegate/FastDelegateBind.h
@@ -0,0 +1,243 @@
+// FastDelegateBind.h
+// Helper file for FastDelegates. Provides bind() function, enabling
+// FastDelegates to be rapidly compared to programs using boost::function and boost::bind.
+//
+// Documentation is found at http://www.codeproject.com/cpp/FastDelegate.asp
+//
+// Original author: Jody Hagins.
+// Minor changes by Don Clugston.
+//
+// Warning: The arguments to 'bind' are ignored! No actual binding is performed.
+// The behaviour is equivalent to boost::bind only when the basic placeholder
+// arguments _1, _2, _3, etc are used in order.
+//
+// HISTORY:
+// 1.4 Dec 2004. Initial release as part of FastDelegate 1.4.
+
+
+#ifndef FASTDELEGATEBIND_H
+#define FASTDELEGATEBIND_H
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+////////////////////////////////////////////////////////////////////////////////
+// FastDelegate bind()
+//
+// bind() helper function for boost compatibility.
+// (Original author: Jody Hagins).
+//
+// Add another helper, so FastDelegate can be a dropin replacement
+// for boost::bind (in a fair number of cases).
+// Note the elipses, because boost::bind() takes place holders
+// but FastDelegate does not care about them. Getting the place holder
+// mechanism to work, and play well with boost is a bit tricky, so
+// we do the "easy" thing...
+// Assume we have the following code...
+// using boost::bind;
+// bind(&Foo:func, &foo, _1, _2);
+// we should be able to replace the "using" with...
+// using fastdelegate::bind;
+// and everything should work fine...
+////////////////////////////////////////////////////////////////////////////////
+
+#ifdef FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX
+
+namespace fastdelegate {
+
+//N=0
+template <class X, class Y, class RetType>
+FastDelegate< RetType ( ) >
+bind(
+ RetType (X::*func)( ),
+ Y * y,
+ ...)
+{
+ return FastDelegate< RetType ( ) >(y, func);
+}
+
+template <class X, class Y, class RetType>
+FastDelegate< RetType ( ) >
+bind(
+ RetType (X::*func)( ) const,
+ Y * y,
+ ...)
+{
+ return FastDelegate< RetType ( ) >(y, func);
+}
+
+//N=1
+template <class X, class Y, class RetType, class Param1>
+FastDelegate< RetType ( Param1 p1 ) >
+bind(
+ RetType (X::*func)( Param1 p1 ),
+ Y * y,
+ ...)
+{
+ return FastDelegate< RetType ( Param1 p1 ) >(y, func);
+}
+
+template <class X, class Y, class RetType, class Param1>
+FastDelegate< RetType ( Param1 p1 ) >
+bind(
+ RetType (X::*func)( Param1 p1 ) const,
+ Y * y,
+ ...)
+{
+ return FastDelegate< RetType ( Param1 p1 ) >(y, func);
+}
+
+//N=2
+template <class X, class Y, class RetType, class Param1, class Param2>
+FastDelegate< RetType ( Param1 p1, Param2 p2 ) >
+bind(
+ RetType (X::*func)( Param1 p1, Param2 p2 ),
+ Y * y,
+ ...)
+{
+ return FastDelegate< RetType ( Param1 p1, Param2 p2 ) >(y, func);
+}
+
+template <class X, class Y, class RetType, class Param1, class Param2>
+FastDelegate< RetType ( Param1 p1, Param2 p2 ) >
+bind(
+ RetType (X::*func)( Param1 p1, Param2 p2 ) const,
+ Y * y,
+ ...)
+{
+ return FastDelegate< RetType ( Param1 p1, Param2 p2 ) >(y, func);
+}
+
+//N=3
+template <class X, class Y, class RetType, class Param1, class Param2, class Param3>
+FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3 ) >
+bind(
+ RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3 ),
+ Y * y,
+ ...)
+{
+ return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3 ) >(y, func);
+}
+
+template <class X, class Y, class RetType, class Param1, class Param2, class Param3>
+FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3 ) >
+bind(
+ RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3 ) const,
+ Y * y,
+ ...)
+{
+ return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3 ) >(y, func);
+}
+
+//N=4
+template <class X, class Y, class RetType, class Param1, class Param2, class Param3, class Param4>
+FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4 ) >
+bind(
+ RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3, Param4 p4 ),
+ Y * y,
+ ...)
+{
+ return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4 ) >(y, func);
+}
+
+template <class X, class Y, class RetType, class Param1, class Param2, class Param3, class Param4>
+FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4 ) >
+bind(
+ RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3, Param4 p4 ) const,
+ Y * y,
+ ...)
+{
+ return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4 ) >(y, func);
+}
+
+//N=5
+template <class X, class Y, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5>
+FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5 ) >
+bind(
+ RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5 ),
+ Y * y,
+ ...)
+{
+ return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5 ) >(y, func);
+}
+
+template <class X, class Y, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5>
+FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5 ) >
+bind(
+ RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5 ) const,
+ Y * y,
+ ...)
+{
+ return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5 ) >(y, func);
+}
+
+//N=6
+template <class X, class Y, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6>
+FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6 ) >
+bind(
+ RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6 ),
+ Y * y,
+ ...)
+{
+ return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6 ) >(y, func);
+}
+
+template <class X, class Y, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6>
+FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6 ) >
+bind(
+ RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6 ) const,
+ Y * y,
+ ...)
+{
+ return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6 ) >(y, func);
+}
+
+//N=7
+template <class X, class Y, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7>
+FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7 ) >
+bind(
+ RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7 ),
+ Y * y,
+ ...)
+{
+ return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7 ) >(y, func);
+}
+
+template <class X, class Y, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7>
+FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7 ) >
+bind(
+ RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7 ) const,
+ Y * y,
+ ...)
+{
+ return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7 ) >(y, func);
+}
+
+//N=8
+template <class X, class Y, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8>
+FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8 ) >
+bind(
+ RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8 ),
+ Y * y,
+ ...)
+{
+ return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8 ) >(y, func);
+}
+
+template <class X, class Y, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8>
+FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8 ) >
+bind(
+ RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8 ) const,
+ Y * y,
+ ...)
+{
+ return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8 ) >(y, func);
+}
+
+
+#endif //FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX
+
+} // namespace fastdelegate
+
+#endif // !defined(FASTDELEGATEBIND_H)
+
diff --git a/emb/pastilda/lib/libopencm3_cpp_extensions b/emb/pastilda/lib/libopencm3_cpp_extensions
-Subproject e42767a7ecc580f0ede93c7c4ff5484e60f7d2a
+Subproject c24dac270a8b7d91184185a7af5e6f8a3ff1b00
diff --git a/emb/pastilda/lib/libopenfat/bpb.h b/emb/pastilda/lib/libopenfat/bpb.h
deleted file mode 100644
index 6593f14..0000000
--- a/emb/pastilda/lib/libopenfat/bpb.h
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * This file is part of the openfat project.
- *
- * Copyright (C) 2011 Department of Physics, University of Otago
- * Written by Gareth McMullin <gareth@blacksphere.co.nz>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/* Boot Sector / BIOS Parameter Block definitions.
- * Convenience functions for calculations.
- */
-
-#ifndef __BPB_H
-#define __BPB_H
-
-#include <stdint.h>
-#include "openfat/leaccess.h"
-
-/* Boot sector fields common to FAT12/FAT16/FAT32 */
-struct bpb_common {
- uint8_t boot_jmp[3];
- char oem_name[8];
- uint16_t bytes_per_sector;
- uint8_t sectors_per_cluster;
- uint16_t reserved_sector_count;
- uint8_t num_fats;
- uint16_t root_entry_count;
- uint16_t total_sectors_16;
- uint8_t media;
- uint16_t fat_size_16;
- uint16_t sectors_per_track;
- uint16_t num_heads;
- uint32_t hidden_sectors;
- uint32_t total_sectors_32;
-} __attribute__((packed));
-
-/* Boot sector fields only in FAT12/FAT16 */
-struct bpb_fat12_16 {
- struct bpb_common common;
- uint8_t drive_num;
- uint8_t Reserved1;
- uint8_t boot_sig;
- uint32_t volume_id;
- char volume_label[11];
- char fs_type[8];
-} __attribute__((packed));
-
-/* Boot sector fields only in FAT32 */
-struct bpb_fat32 {
- struct bpb_common common;
- uint32_t fat_size_32;
- uint16_t ext_flags;
- uint16_t fs_version;
- uint32_t root_cluster;
- uint16_t fs_info;
- uint16_t bk_boot_sec;
- uint8_t Reserved[12];
- uint8_t drive_num;
- uint8_t Reserved1;
- uint8_t boot_sig;
- uint32_t volume_id;
- char volume_label[11];
- char fs_type[8];
-} __attribute__((packed));
-
-
-static inline uint32_t
-_bpb_root_dir_sectors(struct bpb_common *bpb)
-{
- return ((__get_le16(&bpb->root_entry_count) * 32) +
- (__get_le16(&bpb->bytes_per_sector) - 1)) /
- __get_le16(&bpb->bytes_per_sector);
-}
-
-static inline uint32_t
-_bpb_fat_size(struct bpb_common *bpb)
-{
- uint32_t fat_size = __get_le16(&bpb->fat_size_16);
- if(fat_size == 0)
- fat_size = __get_le32(&((struct bpb_fat32 *)bpb)->fat_size_32);
-
- return fat_size;
-}
-
-static inline uint32_t
-_bpb_first_data_sector(struct bpb_common *bpb)
-{
- return __get_le16(&bpb->reserved_sector_count) +
- (bpb->num_fats * _bpb_fat_size(bpb))
- + _bpb_root_dir_sectors(bpb);
-}
-
-static inline uint32_t
-_bpb_first_sector_of_cluster(struct bpb_common *bpb, uint32_t n)
-{
- return ((n - 2) * bpb->sectors_per_cluster) +
- _bpb_first_data_sector(bpb);
-}
-
-enum fat_type {
- FAT_TYPE_FAT12 = 12,
- FAT_TYPE_FAT16 = 16,
- FAT_TYPE_FAT32 = 32,
-};
-
-static inline uint32_t _bpb_cluster_count(struct bpb_common *bpb)
-{
- uint32_t tot_sec = __get_le16(&bpb->total_sectors_16);
- if(tot_sec == 0)
- tot_sec = __get_le32(&bpb->total_sectors_32);
-
- uint32_t data_sec = tot_sec -
- __get_le16(&bpb->reserved_sector_count) -
- (bpb->num_fats * _bpb_fat_size(bpb)) -
- _bpb_root_dir_sectors(bpb);
-
- return data_sec / bpb->sectors_per_cluster;
-}
-
-/* FAT type is determined by count of clusters */
-static inline enum fat_type
-fat_type(struct bpb_common *bpb)
-{
- uint32_t cluster_count = _bpb_cluster_count(bpb);
- if(cluster_count < 4085) {
- return FAT_TYPE_FAT12;
- } else if(cluster_count < 65525) {
- return FAT_TYPE_FAT16;
- }
- return FAT_TYPE_FAT32;
-}
-
-#endif
-
diff --git a/emb/pastilda/lib/libopenfat/direntry.c b/emb/pastilda/lib/libopenfat/direntry.c
deleted file mode 100644
index 46dfc35..0000000
--- a/emb/pastilda/lib/libopenfat/direntry.c
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * This file is part of the openfat project.
- *
- * Copyright (C) 2011 Department of Physics, University of Otago
- * Written by Gareth McMullin <gareth@blacksphere.co.nz>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/* FAT Directory .
- */
-
-#include <string.h>
-#include <ctype.h>
-#include <errno.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-#include "openfat.h"
-
-#include "openfat/leaccess.h"
-#include "openfat/blockdev.h"
-#include "fat_core.h"
-#include "direntry.h"
-
-#define LONG_NAME_SUPPORT
-
-#ifdef LONG_NAME_SUPPORT
-uint8_t _fat_dirent_chksum(uint8_t *dosname)
-{
- uint8_t sum = 0;
- int i;
-
- for (i = 0; i < 11; i++)
- sum = ((sum & 1) ? 0x80 : 0) + (sum >> 1) + *dosname++;
-
- return sum;
-}
-
-/* Used to convert W95 UTF-16 filenames to ascii.
- * 0 means terminating null reached.
- * 1 means converted to end on input.
- * 2 means conversion error.
- */
-static int ascii_from_utf16(char *ascii, const uint16_t *utf16, int count)
-{
- uint16_t tmp;
- while(count--) {
- tmp = __get_le16(utf16++);
- if(tmp > 127)
- return 2;
- *ascii++ = tmp;
- if(tmp == 0)
- return 0;
- }
- return 1;
-}
-#endif
-
-int fat_readdir(struct fat_file_handle *h, struct dirent *ent)
-{
-#ifdef LONG_NAME_SUPPORT
- uint16_t csum = -1;
-#endif
- struct fat_sdirent fatent;
- int i, j;
-
- while(fat_read(h, &fatent, sizeof(fatent)) == sizeof(fatent)) {
-
- if(fatent.name[0] == 0)
- return -1; /* Empty entry, end of directory */
- if(fatent.name[0] == (char)0xe5)
- continue; /* Deleted entry */
- if(fatent.attr == FAT_ATTR_VOLUME_ID)
- continue; /* Ignore volume id entry */
- if(fatent.attr == FAT_ATTR_LONG_NAME) {
-#ifdef LONG_NAME_SUPPORT
- struct fat_ldirent *ld = (void*)&fatent;
- if(ld->ord & FAT_LAST_LONG_ENTRY) {
- memset(ent->d_name, 0, sizeof(ent->d_name));
- csum = ld->checksum;
- }
- if(csum != ld->checksum) /* Abandon orphaned entry */
- csum = -1;
-
- i = ((ld->ord & 0x3f) - 1) * 13;
-
- /* If entries can't be converted to ASCII, abandon
- * the long filename. DOS 8.3 name will be returned.
- * Not pretty... */
- switch(ascii_from_utf16(&ent->d_name[i], ld->name1, 5))
- { case 0: continue; case 2: csum = -1; }
- switch(ascii_from_utf16(&ent->d_name[i+5], ld->name2, 6))
- { case 0: continue; case 2: csum = -1; }
- switch(ascii_from_utf16(&ent->d_name[i+11], ld->name3, 2))
- { case 0: continue; case 2: csum = -1; }
-#endif
- continue;
- }
-#ifdef LONG_NAME_SUPPORT
- if(csum != _fat_dirent_chksum((uint8_t*)fatent.name))
- ent->d_name[0] = 0;
-
- if(ent->d_name[0] == 0) {
-#endif
- for(i = 0, j = 0; i < 11; i++, j++) {
- ent->d_name[j] = tolower(fatent.name[i]);
- if(fatent.name[i] == ' ') {
- ent->d_name[j] = '.';
- while((fatent.name[++i] == ' ') && (i < 11));
- }
- }
- if(ent->d_name[j-1] == '.')
- ent->d_name[j-1] = 0;
-
- ent->d_name[j] = 0;
-#ifdef LONG_NAME_SUPPORT
- }
-#endif
- /* Non-standard */
- ent->fat_attr = fatent.attr;
- memcpy(ent->fat_sname, fatent.name, 11);
-
- return 0;
- }
- return -1;
-}
-
-/* Seek to a place in the directory suitable for writing 'entries' new
- * directory entries. Called when creating files. */
-int _fat_dir_seek_empty(struct fat_file_handle *dir, int entries)
-{
- uint32_t pos = 0;
- struct fat_sdirent ent;
- int i = 0;
-
- fat_lseek(dir, 0, SEEK_SET);
-
- while(fat_read(dir, &ent, sizeof(ent)) == sizeof(ent)) {
- if(ent.name[0] == 0) /* Empty entry, end of directory */
- break;
- if(ent.name[0] == (char)0xe5) { /* Deleted entry */
- i++;
- if(i == entries)
- break;
- continue;
- }
- i = 0;
- pos = dir->position;
- }
-
- fat_lseek(dir, pos, SEEK_SET);
- return 0;
-}
-
-static int fat_comparesfn(const char * name, const char *fatname)
-{
- char canonname[11];
- int i;
-
- memset(canonname, ' ', sizeof(canonname));
- if(name[0] == '.') {
- /* Special case:
- * Only legal names are '.' and '..' */
- memcpy(canonname, name, strlen(name));
- name += strlen(name);
- } else for(i = 0; (i < 11) && *name && (*name != '/'); i++) {
- if(*name == '.') {
- if(i < 8) continue;
- if(i == 8) name++;
- }
- canonname[i] = toupper(*name++);
- }
- return ((*name == 0) || (*name == '/')) && !memcmp(canonname, fatname, 11);
-}
-
-int fat_open(struct fat_vol_handle *vol, const char *name, int flags,
- struct fat_file_handle *file)
-{
- struct fat_file_handle *dir = (struct fat_file_handle*)&vol->cwd;
- struct dirent dirent;
-
- /* FIXME: Implement flags O_RDONLY, O_WRONLY, O_RDWR. */
-
- if(strcmp(name, ".") == 0) {
- /* Special case needed for root dir with no '.' entry */
- memcpy(file, &vol->cwd, sizeof(*file));
- return 0;
- }
-
- fat_lseek(dir, 0, SEEK_SET);
- while(fat_readdir(dir, &dirent) == 0) {
-
- /* Check for name match */
- if((strcmp(name, dirent.d_name) == 0) ||
- fat_comparesfn(name, dirent.fat_sname)) {
- /* reread on-disk directory entry */
- struct fat_sdirent fatent;
- uint32_t sector;
- uint16_t offset;
- /* Rewind directory one entry */
- fat_lseek(dir, -sizeof(fatent), SEEK_CUR);
- _fat_file_sector_offset(dir, &sector, &offset);
- if(fat_read(dir, &fatent, sizeof(fatent)) != 32)
- return -EIO;
-
- _fat_file_init(dir->fat, &fatent, file);
- file->flags = flags;
- if(!(fatent.attr & FAT_ATTR_DIRECTORY)) {
- file->dirent_sector = sector;
- file->dirent_offset = offset;
- } else if(!file->first_cluster) {
- /* Check for special case of root dir */
- _fat_file_root(dir->fat, file);
- }
- return 0;
- }
- }
- return -ENOENT;
-}
-
-int fat_chdir(struct fat_vol_handle *vol, const char *name)
-{
- return fat_open(vol, name, 0, &vol->cwd);
-}
-
diff --git a/emb/pastilda/lib/libopenfat/direntry.h b/emb/pastilda/lib/libopenfat/direntry.h
deleted file mode 100644
index 3ea00cb..0000000
--- a/emb/pastilda/lib/libopenfat/direntry.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * This file is part of the openfat project.
- *
- * Copyright (C) 2011 Department of Physics, University of Otago
- * Written by Gareth McMullin <gareth@blacksphere.co.nz>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/* FAT Directory entry definitions.
- */
-#ifndef __DIRENTRY_H
-#define __DIRENTRY_H
-
-#include <stdint.h>
-
-struct fat_sdirent {
- char name[11]; /* DOS file name 8.3 */
- uint8_t attr;
- uint8_t Reserved;
- uint8_t create_time_fine;
- uint16_t create_time;
- uint16_t create_date;
- uint16_t access_date;
- uint16_t cluster_hi;
- uint16_t write_time;
- uint16_t write_date;
- uint16_t cluster_lo;
- uint32_t size;
-} __attribute__((packed));
-
-
-#define FAT_LAST_LONG_ENTRY 0x40
-
-/* W95 long file name entries. Characters are in UTF-16. */
-struct fat_ldirent {
- uint8_t ord;
- uint16_t name1[5];
- uint8_t attr;
- uint8_t type;
- uint8_t checksum;
- uint16_t name2[6];
- uint16_t cluster_lo;
- uint16_t name3[2];
-} __attribute__((packed));
-
-uint8_t _fat_dirent_chksum(uint8_t *dosname);
-int _fat_dir_seek_empty(struct fat_file_handle *dir, int entries);
-
-#endif
-
diff --git a/emb/pastilda/lib/libopenfat/fat_core.c b/emb/pastilda/lib/libopenfat/fat_core.c
deleted file mode 100644
index 61f2143..0000000
--- a/emb/pastilda/lib/libopenfat/fat_core.c
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- * This file is part of the openfat project.
- *
- * Copyright (C) 2011 Department of Physics, University of Otago
- * Written by Gareth McMullin <gareth@blacksphere.co.nz>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/* FAT Filesystem core implementation
- */
-
-#include <stdint.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-
-#include "openfat.h"
-
-#include "openfat/blockdev.h"
-#include "openfat/leaccess.h"
-#include "bpb.h"
-#include "fat_core.h"
-
-/* Build time configuration */
-#define MAX_SECTOR_SIZE 512
-
-uint8_t _fat_sector_buf[MAX_SECTOR_SIZE];
-struct _fat_cache _fat_cache;
-
-int fat_vol_init(const struct block_device *dev, struct fat_vol_handle *h)
-{
- struct bpb_common *bpb = (void *)&_fat_sector_buf;
-
- memset(h, 0, sizeof(*h));
- h->dev = dev;
-
- FAT_GET_SECTOR(h, 0);
-
- h->type = fat_type(bpb);
- h->cluster_count = _bpb_cluster_count(bpb);
- h->bytes_per_sector = __get_le16(&bpb->bytes_per_sector);
- h->sectors_per_cluster = bpb->sectors_per_cluster;
- h->first_data_sector = _bpb_first_data_sector(bpb);
- h->reserved_sector_count = __get_le16(&bpb->reserved_sector_count);
- h->num_fats = bpb->num_fats;
- h->fat_size = _bpb_fat_size(bpb);
- h->last_cluster_alloc = 2;
- if(h->type == FAT_TYPE_FAT32) {
- struct bpb_fat32 *bpb32 = (void *)&_fat_sector_buf;
- h->fat32.root_cluster = __get_le32(&bpb32->root_cluster);
- } else {
- h->fat12_16.root_sector_count = _bpb_root_dir_sectors(bpb);
- h->fat12_16.root_first_sector = _bpb_first_data_sector(bpb) -
- h->fat12_16.root_sector_count;
- }
- _fat_file_root(h, &h->cwd);
-
- return 0;
-}
-
-uint32_t _fat_get_next_cluster(const struct fat_vol_handle *h, uint32_t cluster)
-{
- uint32_t offset;
- uint32_t sector;
-
- if(h->type == FAT_TYPE_FAT12)
- offset = cluster + (cluster / 2);
- else if(h->type == FAT_TYPE_FAT16)
- offset = cluster * 2;
- else if(h->type == FAT_TYPE_FAT32)
- offset = cluster * 4;
-
- sector = h->reserved_sector_count + (offset / h->bytes_per_sector);
- offset %= h->bytes_per_sector;
-
- FAT_GET_SECTOR(h, sector);
-
- if(h->type == FAT_TYPE_FAT12) {
- uint32_t next;
- if(offset == (uint32_t)h->bytes_per_sector - 1) {
- /* Fat entry is over sector boundary */
- next = _fat_sector_buf[offset];
- FAT_GET_SECTOR(h, sector + 1);
- next += _fat_sector_buf[0] << 8;
- } else {
- next = __get_le16((uint16_t*)(_fat_sector_buf + offset));
- }
- if(cluster & 1)
- return next >> 4;
- else
- return next & 0xFFF;
- } else if(h->type == FAT_TYPE_FAT16) {
- return __get_le16((uint16_t*)(_fat_sector_buf + offset));
- } else if(h->type == FAT_TYPE_FAT32) {
- return __get_le32((uint32_t*)(_fat_sector_buf + offset)) & 0x0FFFFFFF;
- }
- /* We shouldn't get here... */
- return 0;
-}
-
-void _fat_file_root(struct fat_vol_handle *fat,
- struct fat_file_handle *h)
-{
- memset(h, 0, sizeof(*h));
- h->fat = fat;
-
- if(fat->type == FAT_TYPE_FAT32) {
- h->first_cluster = fat->fat32.root_cluster;
- } else {
- /* FAT12/FAT16 root directory */
- h->root_flag = 1;
- h->first_cluster = fat->fat12_16.root_first_sector;
- h->size = h->fat->fat12_16.root_sector_count * h->fat->bytes_per_sector;
- }
- h->cur_cluster = h->first_cluster;
-}
-
-void _fat_file_init(struct fat_vol_handle *fat,
- const struct fat_sdirent *dirent,
- struct fat_file_handle *h)
-{
- memset(h, 0, sizeof(*h));
- h->fat = fat;
- h->first_cluster = ((uint32_t)__get_le16(&dirent->cluster_hi) << 16) |
- __get_le16(&dirent->cluster_lo);
- h->size = __get_le32(&dirent->size);
- h->cur_cluster = h->first_cluster;
-}
-
-off_t fat_lseek(struct fat_file_handle *h, off_t offset, int whence)
-{
- h->cur_cluster = h->first_cluster;
-
- switch(whence) {
- case SEEK_SET:
- break;
- case SEEK_CUR:
- offset += h->position;
- break;
- case SEEK_END:
- offset += h->size;
- break;
- default:
- return -1;
- }
-
- if(h->size && ((uint32_t)offset > h->size))
- offset = h->size;
-
- h->position = offset;
-
- if(h->root_flag) { /* FAT12/16 root dir isn't a cluster chain */
- return h->position;
- }
-
- /* Iterate over cluster chain to find cluster */
- while(offset >= (h->fat->sectors_per_cluster * h->fat->bytes_per_sector)) {
- h->cur_cluster = _fat_get_next_cluster(h->fat, h->cur_cluster);
- offset -= h->fat->sectors_per_cluster * h->fat->bytes_per_sector;
- }
-
- return h->position;
-}
-
-void _fat_file_sector_offset(struct fat_file_handle *h, uint32_t *sector,
- uint16_t *offset)
-{
- if(h->root_flag) {
- /* FAT12/FAT16 root directory */
- *sector = h->cur_cluster +
- (h->position / h->fat->bytes_per_sector);
- } else {
- *sector = fat_first_sector_of_cluster(h->fat, h->cur_cluster);
- *sector += (h->position / h->fat->bytes_per_sector) %
- h->fat->sectors_per_cluster;
- }
- *offset = h->position % h->fat->bytes_per_sector;
-}
-
-#define MIN(x, y) (((x) < (y))?(x):(y))
-int fat_read(struct fat_file_handle *h, void *buf, int size)
-{
- int i;
- uint32_t sector;
- uint16_t offset;
-
- _fat_file_sector_offset(h, &sector, &offset);
-
- /* Don't read past end of file */
- if(h->size && ((h->position + size) > h->size))
- size = h->size - h->position;
-
- for(i = 0; i < size; ) {
- uint16_t chunk = MIN(h->fat->bytes_per_sector - offset, size - i);
- FAT_GET_SECTOR(h->fat, sector);
- memcpy(buf + i, _fat_sector_buf + offset, chunk);
- h->position += chunk;
- i += chunk;
- if((h->position % h->fat->bytes_per_sector) != 0)
- /* we didn't read until the end of the sector... */
- break;
- offset = 0;
- sector++;
- if(h->root_flag) /* FAT12/16 isn't a cluster chain */
- continue;
- if((sector % h->fat->sectors_per_cluster) == 0) {
- /* Go to next cluster... */
- h->cur_cluster = _fat_get_next_cluster(h->fat,
- h->cur_cluster);
- if(h->cur_cluster == fat_eoc(h->fat))
- return i;
- sector = fat_first_sector_of_cluster(h->fat,
- h->cur_cluster);
- }
- }
-
- return i;
-}
-
diff --git a/emb/pastilda/lib/libopenfat/fat_core.h b/emb/pastilda/lib/libopenfat/fat_core.h
deleted file mode 100644
index 4c681b3..0000000
--- a/emb/pastilda/lib/libopenfat/fat_core.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * This file is part of the openfat project.
- *
- * Copyright (C) 2011 Department of Physics, University of Otago
- * Written by Gareth McMullin <gareth@blacksphere.co.nz>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/* FAT Filesystem core implementation, private interface
- */
-#ifndef __FAT_CORE_H
-#define __FAT_CORE_H
-
-#include "bpb.h"
-#include "direntry.h"
-
-extern uint8_t _fat_sector_buf[];
-
-extern struct _fat_cache {
- /* Working sector buffer, use _fat_sector_buf by default. */
- uint8_t *buf;
-
- /* Sector and block device for current contents of buf. */
- const void *bldev;
- uint32_t sector;
-
- /* Non-zero if buffer is out-of-sync with the physical medium. */
- uint8_t dirty;
-} _fat_cache;
-
-static inline uint32_t
-fat_eoc(const struct fat_vol_handle *fat)
-{
- switch (fat->type) {
- case FAT_TYPE_FAT12:
- return 0x0FF8;
- case FAT_TYPE_FAT16:
- return 0xFFF8;
- case FAT_TYPE_FAT32:
- return 0x0FFFFFF8;
- }
- return -1;
-}
-
-static inline uint32_t
-fat_first_sector_of_cluster(const struct fat_vol_handle *fat, uint32_t n)
-{
- return ((n - 2) * fat->sectors_per_cluster) + fat->first_data_sector;
-}
-
-uint32_t
-_fat_get_next_cluster(const struct fat_vol_handle *h, uint32_t cluster);
-
-void _fat_file_root(struct fat_vol_handle *fat, struct fat_file_handle *h);
-void _fat_file_init(struct fat_vol_handle *fat, const struct fat_sdirent *,
- struct fat_file_handle *h);
-
-void _fat_file_sector_offset(struct fat_file_handle *h, uint32_t *sector,
- uint16_t *offset);
-
-int _fat_dir_create_file(struct fat_vol_handle *vol, const char *name,
- uint8_t attr, struct fat_file_handle *file);
-
-#define FAT_FLUSH_SECTOR() do {\
- if(_fat_cache.dirty) \
- if(block_write_sectors(_fat_cache.bldev, _fat_cache.sector, \
- 1, _fat_sector_buf) != 1) \
- return -EIO; \
- _fat_cache.dirty = 0; \
-} while(0)
-
-#define FAT_GET_SECTOR(fat, sectorn) do {\
- if((_fat_cache.bldev==(fat)->dev) && (_fat_cache.sector==(sectorn)))\
- break; \
-\
- FAT_FLUSH_SECTOR(); \
-\
- _fat_cache.bldev = (fat)->dev; \
- _fat_cache.sector = (sectorn); \
-\
- if(block_read_sectors((fat)->dev, (sectorn), 1, _fat_sector_buf) != 1)\
- return -EIO; \
-} while(0)
-
-#define FAT_PUT_SECTOR(fat, sectorn) do {\
- if((_fat_cache.bldev!=(fat)->dev) || (_fat_cache.sector!=(sectorn)))\
- FAT_FLUSH_SECTOR(); \
-\
- _fat_cache.bldev = (fat)->dev; \
- _fat_cache.sector = (sectorn); \
- _fat_cache.dirty = 1; \
-} while(0)
-
-
-#endif
-
diff --git a/emb/pastilda/lib/libopenfat/mbr.c b/emb/pastilda/lib/libopenfat/mbr.c
deleted file mode 100644
index 6697746..0000000
--- a/emb/pastilda/lib/libopenfat/mbr.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * This file is part of the openfat project.
- *
- * Copyright (C) 2011 Department of Physics, University of Otago
- * Written by Gareth McMullin <gareth@blacksphere.co.nz>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/* Master boot record.
- */
-
-#include <stdint.h>
-
-#include "openfat/leaccess.h"
-#include "openfat/blockdev.h"
-#include "openfat/mbr.h"
-
-/* In fat_core.c */
-extern uint8_t _fat_sector_buf[];
-
-static int mbr_read_sectors(const struct block_device *dev,
- uint32_t sector, uint32_t count, void *buf)
-{
- struct block_mbr_partition *part = (void*)dev;
-
- return block_read_sectors(part->whole,
- part->first_lba + sector, count, buf);
-}
-
-static int mbr_write_sectors(const struct block_device *dev,
- uint32_t sector, uint32_t count, const void *buf)
-{
- struct block_mbr_partition *part = (void*)dev;
-
- return block_write_sectors(part->whole,
- part->first_lba + sector, count, buf);
-}
-
-int mbr_partition_init(struct block_mbr_partition *part,
- struct block_device *whole, uint8_t part_index)
-{
- struct mbr_partition *part_table = (void*)&_fat_sector_buf[446];
- /* Read MBR from whole device */
- if(block_read_sectors(whole, 0, 1, _fat_sector_buf) != 1)
- return -1;
-
- part->whole = whole;
-
- part->first_lba = __get_le32(&part_table[part_index].first_lba);
- part->sector_count = __get_le32(&part_table[part_index].sector_count);
-
- part->bldev.get_sector_size = whole->get_sector_size;
- part->bldev.read_sectors = mbr_read_sectors;
- part->bldev.write_sectors = mbr_write_sectors;
-
- return 0;
-}
-
-
diff --git a/emb/pastilda/lib/libopenfat/openfat.h b/emb/pastilda/lib/libopenfat/openfat.h
deleted file mode 100644
index ec4b856..0000000
--- a/emb/pastilda/lib/libopenfat/openfat.h
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * This file is part of the openfat project.
- *
- * Copyright (C) 2011 Department of Physics, University of Otago
- * Written by Gareth McMullin <gareth@blacksphere.co.nz>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/** \file openfat.h
- * \brief FAT Filesystem implementation, public interface.
- */
-
-#ifndef __OPENFAT_H
-#define __OPENFAT_H
-
-#include <stdint.h>
-
-#include <sys/stat.h>
-
-#include "openfat/blockdev.h"
-
-/* Forward declarations of private structures. */
-
-/** \brief Structure used internally for FAT volume state.
- * Do not access directly. Structure has no public fields.
- */
-typedef struct fat_vol_handle FatVol;
-
-/** \brief Structure used internally for FAT file state.
- * Do not access directly. Structure has no public fields.
- */
-typedef struct fat_file_handle FatFile;
-
-/** \brief Mount a FAT volume.
- *
- * Initialise a handle for access to a FAT filesystem on the specified
- * block device.
- * \param dev Pointer to block device to mount.
- * \param vol Pointer to filesystem handle to initialise.
- * \return 0 on success.
- */
-int __attribute__((warn_unused_result))
-fat_vol_init(const struct block_device *dev, FatVol *vol);
-
-/** \brief Change current working directory.
- * \param vol Pointer to FAT volume handle.
- * \param name Directory name to change to. Relative to the current dir.
- * \return 0 on success.
- */
-int fat_chdir(FatVol *vol, const char *name);
-/** \brief Create a new directory.
- * \param vol Pointer to FAT volume handle.
- * \param name Directory name to create.
- * \return 0 on success.
- */
-int fat_mkdir(FatVol *vol, const char *name);
-/** \brief Remove an empty directory.
- * \param vol Pointer to FAT volume handle.
- * \param name Directory name to remove.
- * \return 0 on success.
- */
-int fat_rmdir(FatVol *vol, const char *name); /* TODO */
-
-/** \brief Open an existing file.
- * The option O_ASYNC may be passed in flags to surpress the automatic
- * updating of the files directory entry on writes. fat_file_sync() must be
- * called explicitly to update it in this case.
- *
- * This function uses a ::dirent on the stack for iterating over the directory.
- * This is a fairly large structure.
- *
- * \param vol Pointer to FAT volume handle.
- * \param name File name in current directory to open.
- * \param flags O_RDONLY, O_WRONLY, or O_RDWR. (currently not implemented)
- * \param file Pointer to file handle to initialise.
- * \return 0 on success.
- */
-int __attribute__((warn_unused_result))
-fat_open(FatVol *vol, const char *name, int flags, FatFile *file);
-
-/** \brief Create a new file.
- * \see fat_open()
- *
- * \param vol Pointer to FAT volume handle.
- * \param name File name in current directory to create.
- * \param flags O_RDONLY, O_WRONLY, or O_RDWR. (currently not implemented)
- * \param file Pointer to file handle to initialise.
- * \return 0 on success.
- */
-int __attribute__((warn_unused_result))
-fat_create(FatVol *vol, const char *name, int flags, FatFile *file);
-
-#define O_ASYNC 020000
-/** \brief Update an open file's directory entry.
- * This must be called explicitly if a file is opened with the flag O_ASYNC.
- * In this case, updates to the directory entry are surpressed on writes to
- * improve performance.
- * \param file Pointer to file handle from which to read.
- * \return 0 on success.
- */
-int fat_file_sync(FatFile *h);
-
-/** \brief Read from an open file.
- * \param file Pointer to file handle from which to read.
- * \param buf Buffer into which to read.
- * \param size Number of bytes to read.
- * \return Number of bytes read on success, negative on error.
- */
-int __attribute__((warn_unused_result))
-fat_read(FatFile *file, void *buf, int size);
-
-/** \brief Write to an open file.
- * \param file Pointer to file handle into which to write.
- * \param buf Buffer from which to write.
- * \param size Number of bytes to write.
- * \return Number of bytes written on success, negative on error.
- */
-int __attribute__((warn_unused_result))
-fat_write(FatFile *file, const void *buf, int size);
-
-/** \brief Sets the position in an open file.
- * \param file Pointer to file handle to change.
- * \param offset Offset into target file.
- * \param whence One of SEEK_SET, SEEK_CUR, SEEK_END. See Unix documentation.
- * \return New file position on success, negative on error.
- */
-off_t fat_lseek(FatFile *file, off_t offset, int whence);
-
-/** \brief Unlink/delete a file.
- * \param vol Pointer to FAT volume handle.
- * \param name Name of file in current directory to unlink.
- * \return 0 on success.
- */
-int fat_unlink(FatVol *vol, const char *name);
-
-#define FAT_ATTR_READ_ONLY 0x01
-#define FAT_ATTR_HIDDEN 0x02
-#define FAT_ATTR_SYSTEM 0x04
-#define FAT_ATTR_VOLUME_ID 0x08
-#define FAT_ATTR_DIRECTORY 0x10
-#define FAT_ATTR_ARCHIVE 0x20
-#define FAT_ATTR_LONG_NAME 0x0F
-
-/** \brief Public directory entry structure, returned by fat_readdir() */
-struct dirent {
- char d_name[256]; /**< Long file name, POSIX standard. */
- /* Non-standard */
- uint8_t fat_attr; /**< FAT file attributes, non-standard */
- char fat_sname[11]; /**< DOS short filename, non-standard */
-};
-
-/** \brief Read a directory entry.
- * The dirent structure is filled in with the details of the next file in
- * the directory stream pointed to by dir.
- * \param dir Pointer to file handle for the directory to be read.
- * \param ent Pointer to dirent structure for the read entry.
- * \return 0 on success.
- */
-int fat_readdir(FatFile *dir, struct dirent *ent);
-
-
-/* Everything below is private. Applications should not direcly access
- * anything here.
- */
-
-struct fat_file_handle {
- struct fat_vol_handle *fat;
- /* Fields from dir entry */
- uint32_t size;
- uint32_t first_cluster;
- /* Internal state information */
- uint32_t position;
- uint32_t cur_cluster; /* This is used for sector on FAT12/16 root */
- uint8_t root_flag; /* Flag to mark root directory on FAT12/16 */
- int flags;
- /* Reference to dirent */
- uint32_t dirent_sector;
- uint16_t dirent_offset;
-};
-
-struct fat_vol_handle {
- const struct block_device *dev;
- /* FAT type: 12, 16 or 32 */
- int type;
- /* Useful fields from BPB */
- uint16_t bytes_per_sector;
- uint8_t sectors_per_cluster;
- uint16_t reserved_sector_count;
- uint8_t num_fats;
- /* Fields calcuated from BPB */
- uint32_t first_data_sector;
- uint32_t cluster_count;
- uint32_t fat_size;
- union {
- struct {
- uint32_t root_cluster;
- } fat32;
- struct {
- uint16_t root_sector_count;
- uint16_t root_first_sector;
- } fat12_16;
- };
- /* Internal state */
- uint32_t last_cluster_alloc;
- struct fat_file_handle cwd;
-};
-
-#endif
diff --git a/emb/pastilda/lib/libopenfat/openfat/blockdev.h b/emb/pastilda/lib/libopenfat/openfat/blockdev.h
deleted file mode 100644
index ce8b15a..0000000
--- a/emb/pastilda/lib/libopenfat/openfat/blockdev.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * This file is part of the openfat project.
- *
- * Copyright (C) 2011 Department of Physics, University of Otago
- * Written by Gareth McMullin <gareth@blacksphere.co.nz>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/** \file blockdev.h
- * \brief Block device abstraction.
- * Must be implemented by application for a physical device.
- */
-
-#ifndef __BLOCKDEV_H
-#define __BLOCKDEV_H
-
-#include <stdint.h>
-
-/** \brief Structure representing an abstract block device.
- * This abstraction must be provided by the application.
- */
-struct block_device {
- /* Info about the device */
- /** \brief Method to get sector size. */
- uint16_t (*get_sector_size)(const struct block_device *dev);
- /* ... more to be added as needed ... */
-
- /* Actions on the device */
- /** \brief Method to read sectors. */
- int (*read_sectors)(const struct block_device *dev,
- uint32_t sector, uint32_t count, void *buf);
- /** \brief Method to write sectors. */
- int (*write_sectors)(const struct block_device *dev,
- uint32_t sector, uint32_t count, const void *buf);
- /* ... more to be added as needed ... */
-
- /* May be private fields here ... */
-};
-
-/* Convenient wrapper functions */
-static inline uint16_t
-block_get_sector_size(const struct block_device *dev)
-{
- return dev->get_sector_size(dev);
-}
-
-/* Returns the number of sectors read or negative on error */
-static inline int __attribute__((warn_unused_result))
-block_read_sectors(const struct block_device *dev,
- uint32_t sector, uint32_t count, void *buf)
-{
- return dev->read_sectors(dev, sector, count, buf);
-}
-
-/* Returns the number of sectors written or negative on error */
-static inline int __attribute__((warn_unused_result))
-block_write_sectors(const struct block_device *dev,
- uint32_t sector, uint32_t count, const void *buf)
-{
- return dev->write_sectors(dev, sector, count, buf);
-}
-
-#endif
-
diff --git a/emb/pastilda/lib/libopenfat/openfat/leaccess.h b/emb/pastilda/lib/libopenfat/openfat/leaccess.h
deleted file mode 100644
index 6a48955..0000000
--- a/emb/pastilda/lib/libopenfat/openfat/leaccess.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * This file is part of the openfat project.
- *
- * Copyright (C) 2011 Department of Physics, University of Otago
- * Written by Gareth McMullin <gareth@blacksphere.co.nz>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/* Macros for structure access. Host system may be little or big endian,
- * and may not be capable of misaligned access. Always use these for
- * access to the on-disk FAT structures.
- */
-
-#ifndef __LEACCESS_H
-#define __LEACCESS_H
-
-#include <stdint.h>
-
-static inline uint16_t __get_le16(const uint16_t *p)
-{
- return *(uint8_t *)p + (*((uint8_t *)p + 1) << 8);
-}
-
-static inline void __put_le16(uint16_t *p, uint16_t v)
-{
- *(uint8_t *)p = v & 0xff;
- *((uint8_t *)p + 1) = v >> 8;
-}
-
-static inline uint32_t __get_le32(const uint32_t *p)
-{
- return __get_le16((uint16_t *)p) +
- (uint32_t)(__get_le16((const uint16_t *)p + 1) << 16);
-}
-
-static inline void __put_le32(uint32_t *p, uint32_t v)
-{
- __put_le16((uint16_t *)p, v & 0xffff);
- __put_le16((uint16_t *)p + 1, v >> 16);
-}
-
-#ifdef __TEST__
-#include <stdio.h>
-#include <assert.h>
-int main(void)
-{
- const char testdata[] = "\x01\x23\x45\x67";
- printf("%08X\n", __get_le32((uint32_t *)testdata));
- assert(__get_le32((uint32_t *)testdata) == 0x67452301);
- return 0;
-}
-#endif
-
-#endif
-
diff --git a/emb/pastilda/lib/libopenfat/openfat/mbr.h b/emb/pastilda/lib/libopenfat/openfat/mbr.h
deleted file mode 100644
index a9f41f9..0000000
--- a/emb/pastilda/lib/libopenfat/openfat/mbr.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * This file is part of the openfat project.
- *
- * Copyright (C) 2011 Department of Physics, University of Otago
- * Written by Gareth McMullin <gareth@blacksphere.co.nz>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/** \file mbr.h
- * \brief PC Disk Partition Table implementation.
- * This module provides interpretation of the PC Master Boot Record
- * partition table, and provides a block device implementation for
- * partitions given an implementation for the whole disk using wrapper
- * functions.
- */
-
-#ifndef __MBR_H
-#define __MBR_H
-
-#include <stdint.h>
-
-#include "blockdev.h"
-
-struct mbr_partition {
- uint8_t bootable;
- uint8_t first_chs[3];
- uint8_t type;
- uint8_t last_chs[3];
- uint32_t first_lba;
- uint32_t sector_count;
-} __attribute__((packed));
-
-/** \brief Structure representing block device for a PC disk partition.
- * Don't access directly. No public fields. */
-struct block_mbr_partition {
- struct block_device bldev;
- struct block_device *whole;
- uint32_t first_lba;
- uint32_t sector_count;
-};
-
-/** \brief Initialise a partition block device.
- * \param part Pointer to partition block device to initialize.
- * \param whole Pointer to block device for whole media.
- * \param part_index Partition index (0-3).
- * \return 0 on success.
- */
-int mbr_partition_init(struct block_mbr_partition *part,
- struct block_device *whole, uint8_t part_index);
-
-#endif
-
diff --git a/emb/pastilda/lib/libopenfat/openfat/unixlike.h b/emb/pastilda/lib/libopenfat/openfat/unixlike.h
deleted file mode 100644
index cfba7cd..0000000
--- a/emb/pastilda/lib/libopenfat/openfat/unixlike.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * This file is part of the openfat project.
- *
- * Copyright (C) 2011 Department of Physics, University of Otago
- * Written by Gareth McMullin <gareth@blacksphere.co.nz>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * Unix-like API for FAT filesystem access.
- */
-
-#ifndef __UNIXLIKE_H
-#define __UNIXLIKE_H
-
-#include <openfat.h>
-
-#include <stdlib.h>
-
-FatVol * ufat_mount(struct block_device *dev);
-static inline void ufat_umount(FatVol *vol) { free(vol); }
-
-FatFile * ufat_open(FatVol *vol, const char *path, int flags);
-static inline void ufat_close(FatFile *file) { free(file); }
-
-int ufat_stat(FatFile *file, struct stat *stat);
-
-#define ufat_read fat_read
-#define ufat_write fat_write
-
-#define ufat_chdir fat_chdir
-#define ufat_mkdir fat_mkdir
-
-#endif
-
diff --git a/emb/pastilda/lib/libopenfat/unixlike.c b/emb/pastilda/lib/libopenfat/unixlike.c
deleted file mode 100644
index ec2e908..0000000
--- a/emb/pastilda/lib/libopenfat/unixlike.c
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * This file is part of the openfat project.
- *
- * Copyright (C) 2011 Department of Physics, University of Otago
- * Written by Gareth McMullin <gareth@blacksphere.co.nz>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "openfat.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-
-#include "openfat/blockdev.h"
-#include "fat_core.h"
-#include "direntry.h"
-
-struct fat_vol_handle *
-ufat_mount(struct block_device *dev)
-{
- struct fat_vol_handle *vol = malloc(sizeof(*vol));
-
- if(fat_vol_init(dev, vol)) {
- free(vol);
- return NULL;
- }
-
- return vol;
-}
-
-struct fat_file_handle *
-ufat_open(struct fat_vol_handle *fat, const char *path, int flags)
-{
- struct fat_file_handle oldcwd;
-
- if(!path || (path[0] == 0))
- return NULL;
-
- struct fat_file_handle *h = malloc(sizeof(*h));
-
- if(path[0] == '/') {
- _fat_file_root(fat, h);
- path++;
- } else {
- memcpy(h, &fat->cwd, sizeof(*h));
- }
-
- memcpy(&oldcwd, &fat->cwd, sizeof(oldcwd));
- while(path && *path) {
- memcpy(&fat->cwd, h, sizeof(*h));
- if(fat_open(fat, path, flags, h)) {
- free(h);
- memcpy(&fat->cwd, &oldcwd, sizeof(oldcwd));
- return NULL;
- }
- path = strchr(path, '/');
- if(path) path++;
- };
-
- memcpy(&fat->cwd, &oldcwd, sizeof(oldcwd));
-
- return h;
-}
-
-int ufat_stat(struct fat_file_handle *h, struct stat *st)
-{
- struct fat_sdirent *fatent;
-
- memset(st, 0, sizeof(*st));
-
- if(h->dirent_sector == 0) {
- /* Root directory */
- st->st_mode = S_IFDIR;
- return 0;
- }
-
- /* Read direntry sector */
- if(block_read_sectors(h->fat->dev, h->dirent_sector, 1, _fat_sector_buf) != 1)
- return -1;
- fatent = (void*)&_fat_sector_buf[h->dirent_offset];
-
- /* TODO: Fill in timestamps */
-
- if(fatent->attr & FAT_ATTR_DIRECTORY) {
- st->st_mode = S_IFDIR;
- } else {
- st->st_size = __get_le32(&fatent->size);
- }
-
- return 0;
-}
-
diff --git a/emb/pastilda/lib/libopenfat/write.c b/emb/pastilda/lib/libopenfat/write.c
deleted file mode 100644
index 6e9e62f..0000000
--- a/emb/pastilda/lib/libopenfat/write.c
+++ /dev/null
@@ -1,453 +0,0 @@
-/*
- * This file is part of the openfat project.
- *
- * Copyright (C) 2011 Department of Physics, University of Otago
- * Written by Gareth McMullin <gareth@blacksphere.co.nz>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/* FAT Filesystem write support implementation
- */
-#include <string.h>
-#include <ctype.h>
-#include <errno.h>
-
-#include "openfat.h"
-
-#include "fat_core.h"
-
-static uint32_t fat_find_free_cluster(struct fat_vol_handle *h)
-{
- uint32_t i;
-
- for(i = h->last_cluster_alloc; i < h->cluster_count; i++) {
- if(_fat_get_next_cluster(h, i) == 0) {
- h->last_cluster_alloc = i;
- return i;
- }
- }
-
- for(i = 2; i < h->last_cluster_alloc; i++) {
- if(_fat_get_next_cluster(h, i) == 0) {
- h->last_cluster_alloc = i;
- return i;
- }
- }
-
- return 0; /* No free clusters */
-}
-
-static int
-fat32_set_next_cluster(const struct fat_vol_handle *h, uint8_t fat,
- uint32_t cluster, uint32_t next)
-{
- uint32_t offset = cluster * 4;
- uint32_t sector;
-
- sector = h->reserved_sector_count + (fat * h->fat_size) +
- (offset / h->bytes_per_sector);
- offset %= h->bytes_per_sector;
-
- FAT_GET_SECTOR(h, sector);
-
- /* Preserve high nybble */
- next &= 0x0FFFFFFF;
- next |= __get_le32((uint32_t*)(_fat_sector_buf + offset)) & 0xF0000000;
- __put_le32((uint32_t*)(_fat_sector_buf + offset), next);
-
- FAT_PUT_SECTOR(h, sector);
-
- return 0;
-}
-
-static int
-fat16_set_next_cluster(const struct fat_vol_handle *h, uint8_t fat,
- uint16_t cluster, uint16_t next)
-{
- uint32_t offset = cluster * 2;
- uint32_t sector;
-
- sector = h->reserved_sector_count + (fat * h->fat_size) +
- (offset / h->bytes_per_sector);
- offset %= h->bytes_per_sector;
-
- FAT_GET_SECTOR(h, sector);
- __put_le16((uint16_t*)(_fat_sector_buf + offset), next);
- FAT_PUT_SECTOR(h, sector);
-
- return 0;
-}
-
-static int
-fat12_set_next_cluster(const struct fat_vol_handle *h, uint8_t fat,
- uint16_t cluster, uint16_t next)
-{
- uint32_t offset = cluster + (cluster / 2);
- uint32_t sector;
- sector = h->reserved_sector_count + (fat * h->fat_size) +
- (offset / h->bytes_per_sector);
- offset %= h->bytes_per_sector;
-
- FAT_GET_SECTOR(h, sector);
- if(offset == (uint32_t)h->bytes_per_sector - 1) {
- if(cluster & 1) {
- next <<= 4;
- _fat_sector_buf[offset] &= 0x0F;
- _fat_sector_buf[offset] |= next & 0xF0;
- FAT_PUT_SECTOR(h, sector);
- sector++;
- FAT_GET_SECTOR(h, sector);
- _fat_sector_buf[0] = next >> 8;
- } else {
- _fat_sector_buf[offset] = next & 0xFF;
- FAT_PUT_SECTOR(h, sector);
- sector++;
- FAT_GET_SECTOR(h, sector);
- _fat_sector_buf[0] &= 0xF0;
- _fat_sector_buf[0] |= (next >> 8) & 0x0F;
- }
- } else {
- if(cluster & 1) {
- next <<= 4;
- next |= __get_le16((uint16_t*)(_fat_sector_buf + offset)) & 0xF;
- } else {
- next &= 0x0FFF;
- next |= __get_le16((uint16_t*)(_fat_sector_buf + offset)) & 0xF000;
- }
- __put_le16((uint16_t*)(_fat_sector_buf + offset), next);
- }
- FAT_PUT_SECTOR(h, sector);
-
- return 0;
-}
-
-static int
-fat_set_next_cluster(const struct fat_vol_handle *h,
- uint32_t cluster, uint32_t next)
-{
- int ret = 0;
- for(int i = 0; i < h->num_fats; i++) {
- switch(h->type) {
- case FAT_TYPE_FAT12:
- ret |= fat12_set_next_cluster(h, i, cluster, next);
- break;
- case FAT_TYPE_FAT16:
- ret |= fat16_set_next_cluster(h, i, cluster, next);
- break;
- case FAT_TYPE_FAT32:
- ret |= fat32_set_next_cluster(h, i, cluster, next);
- break;
- }
- }
- return ret;
-}
-
-static int32_t fat_alloc_next_cluster(struct fat_vol_handle *h,
- uint32_t cluster, int clear)
-{
- /* Return next if already allocated */
- uint32_t next = _fat_get_next_cluster(h, cluster);
-
- if(next != fat_eoc(h))
- return next;
-
- /* Find free cluster to link to */
- next = fat_find_free_cluster(h);
-
- if(!next) /* No more free clusters */
- return 0;
-
- /* Write end of chain marker in new cluster */
- fat_set_next_cluster(h, next, fat_eoc(h));
- /* Add new cluster to chain */
- fat_set_next_cluster(h, cluster, next);
-
- if(clear) {
- /* Zero new cluster */
- uint32_t sector = fat_first_sector_of_cluster(
- h, next);
- FAT_FLUSH_SECTOR();
- memset(_fat_sector_buf, 0, h->bytes_per_sector);
- for(int i = 0; i < h->sectors_per_cluster; i++) {
- /* How do we report failure here?
- * The cluster has already been allocated.
- */
- int discard = block_write_sectors(h->dev, sector + i, 1,
- _fat_sector_buf);
- (void)discard;
- }
- }
-
- return next;
-}
-
-int fat_file_sync(struct fat_file_handle *h)
-{
- struct fat_sdirent *dirent;
- /* Update directory entry with new size */
- FAT_GET_SECTOR(h->fat, h->dirent_sector);
- dirent = (void*)&_fat_sector_buf[h->dirent_offset];
- __put_le32(&dirent->size, h->size);
- __put_le16(&dirent->cluster_hi, h->first_cluster >> 16);
- __put_le16(&dirent->cluster_lo, h->first_cluster & 0xFFFF);
- FAT_PUT_SECTOR(h->fat, h->dirent_sector);
- FAT_FLUSH_SECTOR();
- return 0;
-}
-
-#define MIN(x, y) (((x) < (y))?(x):(y))
-int fat_write(struct fat_file_handle *h, const void *buf, int size)
-{
- int i;
- uint32_t sector;
- uint16_t offset;
-
- if(!h->cur_cluster && size) {
- /* File was empty, allocate first cluster. */
- h->first_cluster = fat_find_free_cluster(h->fat);
- if(!h->first_cluster)
- return 0;
- h->cur_cluster = h->first_cluster;
- /* Write end of chain marker in new cluster */
- fat_set_next_cluster(h->fat, h->cur_cluster, fat_eoc(h->fat));
- /* Directory entry will be updated with size after the
- * file write is done.
- */
- }
-
- /* Don't write past end of FAT12/FAT16 root directory! */
- if(h->root_flag && ((h->position + size) > h->size))
- size = h->size - h->position;
-
- _fat_file_sector_offset(h, &sector, &offset);
-
- for(i = 0; i < size; ) {
- uint16_t chunk = MIN(h->fat->bytes_per_sector - offset,
- size - i);
- if(chunk < h->fat->bytes_per_sector)
- FAT_GET_SECTOR(h->fat, sector);
- else
- FAT_FLUSH_SECTOR();
-
- memcpy(_fat_sector_buf + offset, buf + i, chunk);
- FAT_PUT_SECTOR(h->fat, sector);
- h->position += chunk;
- i += chunk;
- if((h->position % h->fat->bytes_per_sector) != 0)
- /* we didn't write until the end of the sector... */
- break;
- offset = 0;
- sector++;
- if(h->root_flag) /* FAT12/16 isn't a cluster chain */
- continue;
- if((sector % h->fat->sectors_per_cluster) == 0) {
- /* Go to next cluster... */
- uint32_t next_cluster = fat_alloc_next_cluster(h->fat,
- h->cur_cluster, h->size == 0);
- if(!next_cluster)
- break;
- h->cur_cluster = next_cluster;
- sector = fat_first_sector_of_cluster(h->fat,
- h->cur_cluster);
- }
- }
-
- if(h->dirent_sector && (h->position > h->size)) {
- /* Update directory entry with new size */
- h->size = h->position;
- if(!(h->flags & O_ASYNC))
- fat_file_sync(h);
- }
-
- return i;
-}
-
-static int fat_chain_unlink(const struct fat_vol_handle *vol, uint32_t cluster)
-{
- int ret = 0;
- while(cluster && (cluster != fat_eoc(vol))) {
- uint32_t next = _fat_get_next_cluster(vol, cluster);
- ret |= fat_set_next_cluster(vol, cluster, 0);
- cluster = next;
- }
- return ret;
-}
-
-int fat_unlink(struct fat_vol_handle *vol, const char *name)
-{
- struct fat_file_handle h;
- int ret;
-
- ret = fat_open(vol, name, 0, &h);
- if(ret)
- return ret;
-
- /* Don't try to unlink directories, use fat_rmdir() instead. */
- if(!h.dirent_sector)
- return -EISDIR;
-
- /* Free up cluster chain */
- fat_chain_unlink(vol, h.first_cluster);
-
- /* Mark directory entry as deleted */
- FAT_GET_SECTOR(vol, h.dirent_sector);
- _fat_sector_buf[h.dirent_offset] = 0xE5;
- FAT_PUT_SECTOR(vol, h.dirent_sector);
-
- /* FIXME: Remove long name entries. */
-
- return 0;
-}
-
-/* Build a short name for a long name. n is used if name is too long. */
-static void build_short_name(uint8_t *sname, const char *name, int n)
-{
- int i, j;
-
- memset(sname, ' ', 11);
- for(i = 0; (i < 8) && name[i] && (name[i] != '.'); i++)
- sname[i] = toupper(name[i]);
-
- char *suffix = strrchr(name, '.');
- if(suffix) for(j = 1; (j < 4) && suffix[j]; j++)
- sname[j+7] = toupper(suffix[j]);
-
- if(((i == 8) && (name[i] != '.')) ||
- ((suffix - name) != i)) {
- if(i > 6)
- i = 6;
- sname[i] = '~';
- sname[i+1] = '0' + (n % 10);
- }
-}
-
-/* Create a new zero-length file */
-int _fat_dir_create_file(struct fat_vol_handle *vol, const char *name,
- uint8_t attr, struct fat_file_handle *file)
-{
- /* Check if file already exists */
- if(!fat_open(vol, name, 0, file))
- return -1; /* File exists */
-
- /* Attempt to construct a short name for the file */
- uint8_t sname[12];
- sname[11] = 0; /* fat_open() needs terminating null */
- for(int i = 1; i < 10; i++) {
- build_short_name(sname, name, i);
- if(fat_open(vol, (char*)sname, 0, file))
- break; /* We have a winner */
- sname[0] = ' ';
- }
-
- if(sname[0] == ' ')
- return -1; /* Couldn't find a short name */
-
- /* Find usable space in parent directory */
- _fat_dir_seek_empty(&vol->cwd, (strlen(name) / 13) + 2);
-
- /* Create long name directory entries */
- struct fat_ldirent ld;
- int last = 1;
- memset(&ld, 0, sizeof(ld));
- ld.attr = FAT_ATTR_LONG_NAME;
- for(int i = strlen(name) / 13; i >= 0; i--) {
- ld.ord = i + 1;
- if(last) {
- ld.ord |= FAT_LAST_LONG_ENTRY;
- last = 0;
- }
- int j;
- for(j = 0; j < 5; j++)
- __put_le16(&ld.name1[j], name[i*13 + j]);
- for(j = 0; j < 6; j++)
- __put_le16(&ld.name2[j], name[i*13 + j + 5]);
- for(j = 0; j < 2; j++)
- __put_le16(&ld.name3[j], name[i*13 + j + 11]);
- ld.checksum = _fat_dirent_chksum(sname);
- if(fat_write(&vol->cwd, &ld, sizeof(ld)) != sizeof(ld))
- return -1;
- }
-
- /* Create short name entry */
- struct fat_sdirent fatent;
- memset(&fatent, 0, sizeof(fatent));
- fatent.attr = attr;
- memcpy(&fatent.name, sname, 11);
- /* TODO: Insert timestamp */
- if(attr == FAT_ATTR_DIRECTORY) {
- /* Allocate a cluster for directories */
- uint32_t cluster = fat_find_free_cluster(vol);
- if(!cluster)
- return -1;
- fat_set_next_cluster(vol, cluster, fat_eoc(vol));
- __put_le16(&fatent.cluster_hi, cluster >> 16);
- __put_le16(&fatent.cluster_lo, cluster & 0xFFFF);
- }
- if(fat_write(&vol->cwd, &fatent, sizeof(fatent)) != sizeof(fatent))
- return -1;
-
- return fat_open(vol, name, 0, file);
-}
-
-int fat_mkdir(struct fat_vol_handle *vol, const char *name)
-{
- int ret;
- struct fat_file_handle dir;
- struct fat_sdirent fatent;
- ret = _fat_dir_create_file(vol, name, FAT_ATTR_DIRECTORY, &dir);
- if(ret)
- return ret;
-
- FAT_FLUSH_SECTOR();
- /* Clear out cluster */
- memset(_fat_sector_buf, 0, vol->bytes_per_sector);
- uint32_t sector = fat_first_sector_of_cluster(vol, dir.first_cluster);
- for(int i = 0; i < vol->sectors_per_cluster; i++)
- FAT_PUT_SECTOR(vol, sector + i);
-
- memset(&fatent, 0, sizeof(fatent));
- fatent.attr = FAT_ATTR_DIRECTORY;
- memset(fatent.name, ' ', 11);
-
- /* Create '.' entry */
- fatent.name[0] = '.';
- __put_le16(&fatent.cluster_hi, dir.first_cluster >> 16);
- __put_le16(&fatent.cluster_lo, dir.first_cluster & 0xFFFF);
- ret = fat_write(&dir, &fatent, sizeof(fatent));
- if(ret < 0)
- return ret;
-
- /* Create '..' entry */
- fatent.name[1] = '.';
- if((!vol->cwd.root_flag) &&
- (vol->fat32.root_cluster != vol->cwd.first_cluster)) {
- __put_le16(&fatent.cluster_hi, vol->cwd.first_cluster >> 16);
- __put_le16(&fatent.cluster_lo, vol->cwd.first_cluster & 0xFFFF);
- } else {
- fatent.cluster_hi = 0;
- fatent.cluster_lo = 0;
- }
- ret = fat_write(&dir, &fatent, sizeof(fatent));
- return (ret < 0) ? ret : 0;
-}
-
-int fat_create(struct fat_vol_handle *vol, const char *name, int flags,
- struct fat_file_handle *file)
-{
- int ret = _fat_dir_create_file(vol, name, FAT_ATTR_ARCHIVE, file);
- file->flags = flags;
- return ret;
-}
-
diff --git a/emb/pastilda/lib/miniXML/config.h b/emb/pastilda/lib/miniXML/config.h
new file mode 100644
index 0000000..a748a76
--- /dev/null
+++ b/emb/pastilda/lib/miniXML/config.h
@@ -0,0 +1,95 @@
+/*
+ * "$Id: config.h.in 451 2014-01-04 21:50:06Z msweet $"
+ *
+ * Configuration file for Mini-XML, a small XML-like file parsing library.
+ *
+ * Copyright 2003-2014 by Michael R Sweet.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Michael R Sweet and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "COPYING"
+ * which should have been included with this file. If this file is
+ * missing or damaged, see the license at:
+ *
+ * http://www.msweet.org/projects.php/Mini-XML
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+
+
+/*
+ * Version number...
+ */
+
+#define MXML_VERSION ""
+
+
+/*
+ * Inline function support...
+ */
+
+#define inline
+
+
+/*
+ * Long long support...
+ */
+
+#undef HAVE_LONG_LONG
+
+
+/*
+ * Do we have the snprintf() and vsnprintf() functions?
+ */
+
+#undef HAVE_SNPRINTF
+#undef HAVE_VSNPRINTF
+
+
+/*
+ * Do we have the strXXX() functions?
+ */
+
+#undef HAVE_STRDUP
+
+
+/*
+ * Do we have threading support?
+ */
+
+#undef HAVE_PTHREAD_H
+
+
+/*
+ * Define prototypes for string functions as needed...
+ */
+
+# ifndef HAVE_STRDUP
+extern char *_mxml_strdup(const char *);
+# define strdup _mxml_strdup
+# endif /* !HAVE_STRDUP */
+
+extern char *_mxml_strdupf(const char *, ...);
+extern char *_mxml_vstrdupf(const char *, va_list);
+
+# ifndef HAVE_SNPRINTF
+extern int _mxml_snprintf(char *, size_t, const char *, ...);
+# define snprintf _mxml_snprintf
+# endif /* !HAVE_SNPRINTF */
+
+# ifndef HAVE_VSNPRINTF
+extern int _mxml_vsnprintf(char *, size_t, const char *, va_list);
+# define vsnprintf _mxml_vsnprintf
+# endif /* !HAVE_VSNPRINTF */
+
+/*
+ * End of "$Id: config.h.in 451 2014-01-04 21:50:06Z msweet $".
+ */
diff --git a/emb/pastilda/lib/miniXML/mxml-attr.c b/emb/pastilda/lib/miniXML/mxml-attr.c
new file mode 100644
index 0000000..8e89cc1
--- /dev/null
+++ b/emb/pastilda/lib/miniXML/mxml-attr.c
@@ -0,0 +1,314 @@
+/*
+ * "$Id: mxml-attr.c 451 2014-01-04 21:50:06Z msweet $"
+ *
+ * Attribute support code for Mini-XML, a small XML-like file parsing library.
+ *
+ * Copyright 2003-2014 by Michael R Sweet.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Michael R Sweet and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "COPYING"
+ * which should have been included with this file. If this file is
+ * missing or damaged, see the license at:
+ *
+ * http://www.msweet.org/projects.php/Mini-XML
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "config.h"
+#include "mxml.h"
+
+
+/*
+ * Local functions...
+ */
+
+static int mxml_set_attr(mxml_node_t *node, const char *name,
+ char *value);
+
+
+/*
+ * 'mxmlElementDeleteAttr()' - Delete an attribute.
+ *
+ * @since Mini-XML 2.4@
+ */
+
+void
+mxmlElementDeleteAttr(mxml_node_t *node,/* I - Element */
+ const char *name)/* I - Attribute name */
+{
+ int i; /* Looping var */
+ mxml_attr_t *attr; /* Cirrent attribute */
+
+
+#ifdef DEBUG
+ fprintf(stderr, "mxmlElementDeleteAttr(node=%p, name=\"%s\")\n",
+ node, name ? name : "(null)");
+#endif /* DEBUG */
+
+ /*
+ * Range check input...
+ */
+
+ if (!node || node->type != MXML_ELEMENT || !name)
+ return;
+
+ /*
+ * Look for the attribute...
+ */
+
+ for (i = node->value.element.num_attrs, attr = node->value.element.attrs;
+ i > 0;
+ i --, attr ++)
+ {
+#ifdef DEBUG
+ printf(" %s=\"%s\"\n", attr->name, attr->value);
+#endif /* DEBUG */
+
+ if (!strcmp(attr->name, name))
+ {
+ /*
+ * Delete this attribute...
+ */
+
+ free(attr->name);
+ free(attr->value);
+
+ i --;
+ if (i > 0)
+ memmove(attr, attr + 1, i * sizeof(mxml_attr_t));
+
+ node->value.element.num_attrs --;
+
+ if (node->value.element.num_attrs == 0)
+ free(node->value.element.attrs);
+ return;
+ }
+ }
+}
+
+
+/*
+ * 'mxmlElementGetAttr()' - Get an attribute.
+ *
+ * This function returns NULL if the node is not an element or the
+ * named attribute does not exist.
+ */
+
+const char * /* O - Attribute value or NULL */
+mxmlElementGetAttr(mxml_node_t *node, /* I - Element node */
+ const char *name) /* I - Name of attribute */
+{
+ int i; /* Looping var */
+ mxml_attr_t *attr; /* Cirrent attribute */
+
+
+#ifdef DEBUG
+ fprintf(stderr, "mxmlElementGetAttr(node=%p, name=\"%s\")\n",
+ node, name ? name : "(null)");
+#endif /* DEBUG */
+
+ /*
+ * Range check input...
+ */
+
+ if (!node || node->type != MXML_ELEMENT || !name)
+ return (NULL);
+
+ /*
+ * Look for the attribute...
+ */
+
+ for (i = node->value.element.num_attrs, attr = node->value.element.attrs;
+ i > 0;
+ i --, attr ++)
+ {
+#ifdef DEBUG
+ printf(" %s=\"%s\"\n", attr->name, attr->value);
+#endif /* DEBUG */
+
+ if (!strcmp(attr->name, name))
+ {
+#ifdef DEBUG
+ printf(" Returning \"%s\"!\n", attr->value);
+#endif /* DEBUG */
+ return (attr->value);
+ }
+ }
+
+ /*
+ * Didn't find attribute, so return NULL...
+ */
+
+#ifdef DEBUG
+ puts(" Returning NULL!\n");
+#endif /* DEBUG */
+
+ return (NULL);
+}
+
+
+/*
+ * 'mxmlElementSetAttr()' - Set an attribute.
+ *
+ * If the named attribute already exists, the value of the attribute
+ * is replaced by the new string value. The string value is copied
+ * into the element node. This function does nothing if the node is
+ * not an element.
+ */
+
+void
+mxmlElementSetAttr(mxml_node_t *node, /* I - Element node */
+ const char *name, /* I - Name of attribute */
+ const char *value) /* I - Attribute value */
+{
+ char *valuec; /* Copy of value */
+
+
+#ifdef DEBUG
+ fprintf(stderr, "mxmlElementSetAttr(node=%p, name=\"%s\", value=\"%s\")\n",
+ node, name ? name : "(null)", value ? value : "(null)");
+#endif /* DEBUG */
+
+ /*
+ * Range check input...
+ */
+
+ if (!node || node->type != MXML_ELEMENT || !name)
+ return;
+
+ if (value)
+ valuec = strdup(value);
+ else
+ valuec = NULL;
+
+ if (mxml_set_attr(node, name, valuec))
+ free(valuec);
+}
+
+
+/*
+ * 'mxmlElementSetAttrf()' - Set an attribute with a formatted value.
+ *
+ * If the named attribute already exists, the value of the attribute
+ * is replaced by the new formatted string. The formatted string value is
+ * copied into the element node. This function does nothing if the node
+ * is not an element.
+ *
+ * @since Mini-XML 2.3@
+ */
+
+void
+mxmlElementSetAttrf(mxml_node_t *node, /* I - Element node */
+ const char *name, /* I - Name of attribute */
+ const char *format,/* I - Printf-style attribute value */
+ ...) /* I - Additional arguments as needed */
+{
+ va_list ap; /* Argument pointer */
+ char *value; /* Value */
+
+
+#ifdef DEBUG
+ fprintf(stderr,
+ "mxmlElementSetAttrf(node=%p, name=\"%s\", format=\"%s\", ...)\n",
+ node, name ? name : "(null)", format ? format : "(null)");
+#endif /* DEBUG */
+
+ /*
+ * Range check input...
+ */
+
+ if (!node || node->type != MXML_ELEMENT || !name || !format)
+ return;
+
+ /*
+ * Format the value...
+ */
+
+ va_start(ap, format);
+ value = _mxml_vstrdupf(format, ap);
+ va_end(ap);
+
+ if (!value)
+ mxml_error("Unable to allocate memory for attribute '%s' in element %s!",
+ name, node->value.element.name);
+ else if (mxml_set_attr(node, name, value))
+ free(value);
+}
+
+
+/*
+ * 'mxml_set_attr()' - Set or add an attribute name/value pair.
+ */
+
+static int /* O - 0 on success, -1 on failure */
+mxml_set_attr(mxml_node_t *node, /* I - Element node */
+ const char *name, /* I - Attribute name */
+ char *value) /* I - Attribute value */
+{
+ int i; /* Looping var */
+ mxml_attr_t *attr; /* New attribute */
+
+
+ /*
+ * Look for the attribute...
+ */
+
+ for (i = node->value.element.num_attrs, attr = node->value.element.attrs;
+ i > 0;
+ i --, attr ++)
+ if (!strcmp(attr->name, name))
+ {
+ /*
+ * Free the old value as needed...
+ */
+
+ if (attr->value)
+ free(attr->value);
+
+ attr->value = value;
+
+ return (0);
+ }
+
+ /*
+ * Add a new attribute...
+ */
+
+ if (node->value.element.num_attrs == 0)
+ attr = malloc(sizeof(mxml_attr_t));
+ else
+ attr = realloc(node->value.element.attrs,
+ (node->value.element.num_attrs + 1) * sizeof(mxml_attr_t));
+
+ if (!attr)
+ {
+ mxml_error("Unable to allocate memory for attribute '%s' in element %s!",
+ name, node->value.element.name);
+ return (-1);
+ }
+
+ node->value.element.attrs = attr;
+ attr += node->value.element.num_attrs;
+
+ if ((attr->name = strdup(name)) == NULL)
+ {
+ mxml_error("Unable to allocate memory for attribute '%s' in element %s!",
+ name, node->value.element.name);
+ return (-1);
+ }
+
+ attr->value = value;
+
+ node->value.element.num_attrs ++;
+
+ return (0);
+}
+
+
+/*
+ * End of "$Id: mxml-attr.c 451 2014-01-04 21:50:06Z msweet $".
+ */
diff --git a/emb/pastilda/lib/miniXML/mxml-entity.c b/emb/pastilda/lib/miniXML/mxml-entity.c
new file mode 100644
index 0000000..0d11df6
--- /dev/null
+++ b/emb/pastilda/lib/miniXML/mxml-entity.c
@@ -0,0 +1,449 @@
+/*
+ * "$Id: mxml-entity.c 451 2014-01-04 21:50:06Z msweet $"
+ *
+ * Character entity support code for Mini-XML, a small XML-like
+ * file parsing library.
+ *
+ * Copyright 2003-2014 by Michael R Sweet.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Michael R Sweet and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "COPYING"
+ * which should have been included with this file. If this file is
+ * missing or damaged, see the license at:
+ *
+ * http://www.msweet.org/projects.php/Mini-XML
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "mxml-private.h"
+
+
+/*
+ * 'mxmlEntityAddCallback()' - Add a callback to convert entities to Unicode.
+ */
+
+int /* O - 0 on success, -1 on failure */
+mxmlEntityAddCallback(
+ mxml_entity_cb_t cb) /* I - Callback function to add */
+{
+ _mxml_global_t *global = _mxml_global();
+ /* Global data */
+
+
+ if (global->num_entity_cbs < (int)(sizeof(global->entity_cbs) / sizeof(global->entity_cbs[0])))
+ {
+ global->entity_cbs[global->num_entity_cbs] = cb;
+ global->num_entity_cbs ++;
+
+ return (0);
+ }
+ else
+ {
+ mxml_error("Unable to add entity callback!");
+
+ return (-1);
+ }
+}
+
+
+/*
+ * 'mxmlEntityGetName()' - Get the name that corresponds to the character value.
+ *
+ * If val does not need to be represented by a named entity, NULL is returned.
+ */
+
+const char * /* O - Entity name or NULL */
+mxmlEntityGetName(int val) /* I - Character value */
+{
+ switch (val)
+ {
+ case '&' :
+ return ("amp");
+
+ case '<' :
+ return ("lt");
+
+ case '>' :
+ return ("gt");
+
+ case '\"' :
+ return ("quot");
+
+ default :
+ return (NULL);
+ }
+}
+
+
+/*
+ * 'mxmlEntityGetValue()' - Get the character corresponding to a named entity.
+ *
+ * The entity name can also be a numeric constant. -1 is returned if the
+ * name is not known.
+ */
+
+int /* O - Character value or -1 on error */
+mxmlEntityGetValue(const char *name) /* I - Entity name */
+{
+ int i; /* Looping var */
+ int ch; /* Character value */
+ _mxml_global_t *global = _mxml_global();
+ /* Global data */
+
+
+ for (i = 0; i < global->num_entity_cbs; i ++)
+ if ((ch = (global->entity_cbs[i])(name)) >= 0)
+ return (ch);
+
+ return (-1);
+}
+
+
+/*
+ * 'mxmlEntityRemoveCallback()' - Remove a callback.
+ */
+
+void
+mxmlEntityRemoveCallback(
+ mxml_entity_cb_t cb) /* I - Callback function to remove */
+{
+ int i; /* Looping var */
+ _mxml_global_t *global = _mxml_global();
+ /* Global data */
+
+
+ for (i = 0; i < global->num_entity_cbs; i ++)
+ if (cb == global->entity_cbs[i])
+ {
+ /*
+ * Remove the callback...
+ */
+
+ global->num_entity_cbs --;
+
+ if (i < global->num_entity_cbs)
+ memmove(global->entity_cbs + i, global->entity_cbs + i + 1,
+ (global->num_entity_cbs - i) * sizeof(global->entity_cbs[0]));
+
+ return;
+ }
+}
+
+
+/*
+ * '_mxml_entity_cb()' - Lookup standard (X)HTML entities.
+ */
+
+int /* O - Unicode value or -1 */
+_mxml_entity_cb(const char *name) /* I - Entity name */
+{
+ int diff, /* Difference between names */
+ current, /* Current entity in search */
+ first, /* First entity in search */
+ last; /* Last entity in search */
+ static const struct
+ {
+ const char *name; /* Entity name */
+ int val; /* Character value */
+ } entities[] =
+ {
+ { "AElig", 198 },
+ { "Aacute", 193 },
+ { "Acirc", 194 },
+ { "Agrave", 192 },
+ { "Alpha", 913 },
+ { "Aring", 197 },
+ { "Atilde", 195 },
+ { "Auml", 196 },
+ { "Beta", 914 },
+ { "Ccedil", 199 },
+ { "Chi", 935 },
+ { "Dagger", 8225 },
+ { "Delta", 916 },
+ { "Dstrok", 208 },
+ { "ETH", 208 },
+ { "Eacute", 201 },
+ { "Ecirc", 202 },
+ { "Egrave", 200 },
+ { "Epsilon", 917 },
+ { "Eta", 919 },
+ { "Euml", 203 },
+ { "Gamma", 915 },
+ { "Iacute", 205 },
+ { "Icirc", 206 },
+ { "Igrave", 204 },
+ { "Iota", 921 },
+ { "Iuml", 207 },
+ { "Kappa", 922 },
+ { "Lambda", 923 },
+ { "Mu", 924 },
+ { "Ntilde", 209 },
+ { "Nu", 925 },
+ { "OElig", 338 },
+ { "Oacute", 211 },
+ { "Ocirc", 212 },
+ { "Ograve", 210 },
+ { "Omega", 937 },
+ { "Omicron", 927 },
+ { "Oslash", 216 },
+ { "Otilde", 213 },
+ { "Ouml", 214 },
+ { "Phi", 934 },
+ { "Pi", 928 },
+ { "Prime", 8243 },
+ { "Psi", 936 },
+ { "Rho", 929 },
+ { "Scaron", 352 },
+ { "Sigma", 931 },
+ { "THORN", 222 },
+ { "Tau", 932 },
+ { "Theta", 920 },
+ { "Uacute", 218 },
+ { "Ucirc", 219 },
+ { "Ugrave", 217 },
+ { "Upsilon", 933 },
+ { "Uuml", 220 },
+ { "Xi", 926 },
+ { "Yacute", 221 },
+ { "Yuml", 376 },
+ { "Zeta", 918 },
+ { "aacute", 225 },
+ { "acirc", 226 },
+ { "acute", 180 },
+ { "aelig", 230 },
+ { "agrave", 224 },
+ { "alefsym", 8501 },
+ { "alpha", 945 },
+ { "amp", '&' },
+ { "and", 8743 },
+ { "ang", 8736 },
+ { "apos", '\'' },
+ { "aring", 229 },
+ { "asymp", 8776 },
+ { "atilde", 227 },
+ { "auml", 228 },
+ { "bdquo", 8222 },
+ { "beta", 946 },
+ { "brkbar", 166 },
+ { "brvbar", 166 },
+ { "bull", 8226 },
+ { "cap", 8745 },
+ { "ccedil", 231 },
+ { "cedil", 184 },
+ { "cent", 162 },
+ { "chi", 967 },
+ { "circ", 710 },
+ { "clubs", 9827 },
+ { "cong", 8773 },
+ { "copy", 169 },
+ { "crarr", 8629 },
+ { "cup", 8746 },
+ { "curren", 164 },
+ { "dArr", 8659 },
+ { "dagger", 8224 },
+ { "darr", 8595 },
+ { "deg", 176 },
+ { "delta", 948 },
+ { "diams", 9830 },
+ { "die", 168 },
+ { "divide", 247 },
+ { "eacute", 233 },
+ { "ecirc", 234 },
+ { "egrave", 232 },
+ { "empty", 8709 },
+ { "emsp", 8195 },
+ { "ensp", 8194 },
+ { "epsilon", 949 },
+ { "equiv", 8801 },
+ { "eta", 951 },
+ { "eth", 240 },
+ { "euml", 235 },
+ { "euro", 8364 },
+ { "exist", 8707 },
+ { "fnof", 402 },
+ { "forall", 8704 },
+ { "frac12", 189 },
+ { "frac14", 188 },
+ { "frac34", 190 },
+ { "frasl", 8260 },
+ { "gamma", 947 },
+ { "ge", 8805 },
+ { "gt", '>' },
+ { "hArr", 8660 },
+ { "harr", 8596 },
+ { "hearts", 9829 },
+ { "hellip", 8230 },
+ { "hibar", 175 },
+ { "iacute", 237 },
+ { "icirc", 238 },
+ { "iexcl", 161 },
+ { "igrave", 236 },
+ { "image", 8465 },
+ { "infin", 8734 },
+ { "int", 8747 },
+ { "iota", 953 },
+ { "iquest", 191 },
+ { "isin", 8712 },
+ { "iuml", 239 },
+ { "kappa", 954 },
+ { "lArr", 8656 },
+ { "lambda", 955 },
+ { "lang", 9001 },
+ { "laquo", 171 },
+ { "larr", 8592 },
+ { "lceil", 8968 },
+ { "ldquo", 8220 },
+ { "le", 8804 },
+ { "lfloor", 8970 },
+ { "lowast", 8727 },
+ { "loz", 9674 },
+ { "lrm", 8206 },
+ { "lsaquo", 8249 },
+ { "lsquo", 8216 },
+ { "lt", '<' },
+ { "macr", 175 },
+ { "mdash", 8212 },
+ { "micro", 181 },
+ { "middot", 183 },
+ { "minus", 8722 },
+ { "mu", 956 },
+ { "nabla", 8711 },
+ { "nbsp", 160 },
+ { "ndash", 8211 },
+ { "ne", 8800 },
+ { "ni", 8715 },
+ { "not", 172 },
+ { "notin", 8713 },
+ { "nsub", 8836 },
+ { "ntilde", 241 },
+ { "nu", 957 },
+ { "oacute", 243 },
+ { "ocirc", 244 },
+ { "oelig", 339 },
+ { "ograve", 242 },
+ { "oline", 8254 },
+ { "omega", 969 },
+ { "omicron", 959 },
+ { "oplus", 8853 },
+ { "or", 8744 },
+ { "ordf", 170 },
+ { "ordm", 186 },
+ { "oslash", 248 },
+ { "otilde", 245 },
+ { "otimes", 8855 },
+ { "ouml", 246 },
+ { "para", 182 },
+ { "part", 8706 },
+ { "permil", 8240 },
+ { "perp", 8869 },
+ { "phi", 966 },
+ { "pi", 960 },
+ { "piv", 982 },
+ { "plusmn", 177 },
+ { "pound", 163 },
+ { "prime", 8242 },
+ { "prod", 8719 },
+ { "prop", 8733 },
+ { "psi", 968 },
+ { "quot", '\"' },
+ { "rArr", 8658 },
+ { "radic", 8730 },
+ { "rang", 9002 },
+ { "raquo", 187 },
+ { "rarr", 8594 },
+ { "rceil", 8969 },
+ { "rdquo", 8221 },
+ { "real", 8476 },
+ { "reg", 174 },
+ { "rfloor", 8971 },
+ { "rho", 961 },
+ { "rlm", 8207 },
+ { "rsaquo", 8250 },
+ { "rsquo", 8217 },
+ { "sbquo", 8218 },
+ { "scaron", 353 },
+ { "sdot", 8901 },
+ { "sect", 167 },
+ { "shy", 173 },
+ { "sigma", 963 },
+ { "sigmaf", 962 },
+ { "sim", 8764 },
+ { "spades", 9824 },
+ { "sub", 8834 },
+ { "sube", 8838 },
+ { "sum", 8721 },
+ { "sup", 8835 },
+ { "sup1", 185 },
+ { "sup2", 178 },
+ { "sup3", 179 },
+ { "supe", 8839 },
+ { "szlig", 223 },
+ { "tau", 964 },
+ { "there4", 8756 },
+ { "theta", 952 },
+ { "thetasym", 977 },
+ { "thinsp", 8201 },
+ { "thorn", 254 },
+ { "tilde", 732 },
+ { "times", 215 },
+ { "trade", 8482 },
+ { "uArr", 8657 },
+ { "uacute", 250 },
+ { "uarr", 8593 },
+ { "ucirc", 251 },
+ { "ugrave", 249 },
+ { "uml", 168 },
+ { "upsih", 978 },
+ { "upsilon", 965 },
+ { "uuml", 252 },
+ { "weierp", 8472 },
+ { "xi", 958 },
+ { "yacute", 253 },
+ { "yen", 165 },
+ { "yuml", 255 },
+ { "zeta", 950 },
+ { "zwj", 8205 },
+ { "zwnj", 8204 }
+ };
+
+
+ /*
+ * Do a binary search for the named entity...
+ */
+
+ first = 0;
+ last = (int)(sizeof(entities) / sizeof(entities[0]) - 1);
+
+ while ((last - first) > 1)
+ {
+ current = (first + last) / 2;
+
+ if ((diff = strcmp(name, entities[current].name)) == 0)
+ return (entities[current].val);
+ else if (diff < 0)
+ last = current;
+ else
+ first = current;
+ }
+
+ /*
+ * If we get here, there is a small chance that there is still
+ * a match; check first and last...
+ */
+
+ if (!strcmp(name, entities[first].name))
+ return (entities[first].val);
+ else if (!strcmp(name, entities[last].name))
+ return (entities[last].val);
+ else
+ return (-1);
+}
+
+
+/*
+ * End of "$Id: mxml-entity.c 451 2014-01-04 21:50:06Z msweet $".
+ */
diff --git a/emb/pastilda/lib/miniXML/mxml-file.c b/emb/pastilda/lib/miniXML/mxml-file.c
new file mode 100644
index 0000000..ab4f751
--- /dev/null
+++ b/emb/pastilda/lib/miniXML/mxml-file.c
@@ -0,0 +1,3071 @@
+/*
+ * "$Id: mxml-file.c 467 2016-06-13 00:51:16Z msweet $"
+ *
+ * File loading code for Mini-XML, a small XML-like file parsing library.
+ *
+ * Copyright 2003-2016 by Michael R Sweet.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Michael R Sweet and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "COPYING"
+ * which should have been included with this file. If this file is
+ * missing or damaged, see the license at:
+ *
+ * http://www.msweet.org/projects.php/Mini-XML
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#ifndef WIN32
+# include <unistd.h>
+#endif /* !WIN32 */
+#include "mxml-private.h"
+
+
+/*
+ * Character encoding...
+ */
+
+#define ENCODE_UTF8 0 /* UTF-8 */
+#define ENCODE_UTF16BE 1 /* UTF-16 Big-Endian */
+#define ENCODE_UTF16LE 2 /* UTF-16 Little-Endian */
+
+
+/*
+ * Macro to test for a bad XML character...
+ */
+
+#define mxml_bad_char(ch) ((ch) < ' ' && (ch) != '\n' && (ch) != '\r' && (ch) != '\t')
+
+
+/*
+ * Types and structures...
+ */
+
+typedef int (*_mxml_getc_cb_t)(void *, int *);
+typedef int (*_mxml_putc_cb_t)(int, void *);
+
+typedef struct _mxml_fdbuf_s /**** File descriptor buffer ****/
+{
+ int fd; /* File descriptor */
+ unsigned char *current, /* Current position in buffer */
+ *end, /* End of buffer */
+ buffer[8192]; /* Character buffer */
+} _mxml_fdbuf_t;
+
+
+/*
+ * Local functions...
+ */
+
+static int mxml_add_char(int ch, char **ptr, char **buffer,
+ int *bufsize);
+static int mxml_fd_getc(void *p, int *encoding);
+static int mxml_fd_putc(int ch, void *p);
+static int mxml_fd_read(_mxml_fdbuf_t *buf);
+static int mxml_fd_write(_mxml_fdbuf_t *buf);
+static int mxml_file_getc(void *p, int *encoding);
+static int mxml_file_putc(int ch, void *p);
+static int mxml_get_entity(mxml_node_t *parent, void *p,
+ int *encoding,
+ _mxml_getc_cb_t getc_cb);
+static inline int mxml_isspace(int ch)
+ {
+ return (ch == ' ' || ch == '\t' || ch == '\r' ||
+ ch == '\n');
+ }
+static mxml_node_t *mxml_load_data(mxml_node_t *top, void *p,
+ mxml_load_cb_t cb,
+ _mxml_getc_cb_t getc_cb,
+ mxml_sax_cb_t sax_cb, void *sax_data);
+static int mxml_parse_element(mxml_node_t *node, void *p,
+ int *encoding,
+ _mxml_getc_cb_t getc_cb);
+static int mxml_string_getc(void *p, int *encoding);
+static int mxml_string_putc(int ch, void *p);
+static int mxml_write_name(const char *s, void *p,
+ _mxml_putc_cb_t putc_cb);
+static int mxml_write_node(mxml_node_t *node, void *p,
+ mxml_save_cb_t cb, int col,
+ _mxml_putc_cb_t putc_cb,
+ _mxml_global_t *global);
+static int mxml_write_string(const char *s, void *p,
+ _mxml_putc_cb_t putc_cb);
+static int mxml_write_ws(mxml_node_t *node, void *p,
+ mxml_save_cb_t cb, int ws,
+ int col, _mxml_putc_cb_t putc_cb);
+
+
+/*
+ * 'mxmlLoadFd()' - Load a file descriptor into an XML node tree.
+ *
+ * The nodes in the specified file are added to the specified top node.
+ * If no top node is provided, the XML file MUST be well-formed with a
+ * single parent node like <?xml> for the entire file. The callback
+ * function returns the value type that should be used for child nodes.
+ * If MXML_NO_CALLBACK is specified then all child nodes will be either
+ * MXML_ELEMENT or MXML_TEXT nodes.
+ *
+ * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK,
+ * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading
+ * child nodes of the specified type.
+ */
+
+mxml_node_t * /* O - First node or NULL if the file could not be read. */
+mxmlLoadFd(mxml_node_t *top, /* I - Top node */
+ int fd, /* I - File descriptor to read from */
+ mxml_load_cb_t cb) /* I - Callback function or MXML_NO_CALLBACK */
+{
+ _mxml_fdbuf_t buf; /* File descriptor buffer */
+
+
+ /*
+ * Initialize the file descriptor buffer...
+ */
+
+ buf.fd = fd;
+ buf.current = buf.buffer;
+ buf.end = buf.buffer;
+
+ /*
+ * Read the XML data...
+ */
+
+ return (mxml_load_data(top, &buf, cb, mxml_fd_getc, MXML_NO_CALLBACK, NULL));
+}
+
+
+/*
+ * 'mxmlLoadFile()' - Load a file into an XML node tree.
+ *
+ * The nodes in the specified file are added to the specified top node.
+ * If no top node is provided, the XML file MUST be well-formed with a
+ * single parent node like <?xml> for the entire file. The callback
+ * function returns the value type that should be used for child nodes.
+ * If MXML_NO_CALLBACK is specified then all child nodes will be either
+ * MXML_ELEMENT or MXML_TEXT nodes.
+ *
+ * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK,
+ * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading
+ * child nodes of the specified type.
+ */
+
+mxml_node_t * /* O - First node or NULL if the file could not be read. */
+mxmlLoadFile(mxml_node_t *top, /* I - Top node */
+ FILE *fp, /* I - File to read from */
+ mxml_load_cb_t cb) /* I - Callback function or MXML_NO_CALLBACK */
+{
+ /*
+ * Read the XML data...
+ */
+
+ return (mxml_load_data(top, fp, cb, mxml_file_getc, MXML_NO_CALLBACK, NULL));
+}
+
+
+/*
+ * 'mxmlLoadString()' - Load a string into an XML node tree.
+ *
+ * The nodes in the specified string are added to the specified top node.
+ * If no top node is provided, the XML string MUST be well-formed with a
+ * single parent node like <?xml> for the entire string. The callback
+ * function returns the value type that should be used for child nodes.
+ * If MXML_NO_CALLBACK is specified then all child nodes will be either
+ * MXML_ELEMENT or MXML_TEXT nodes.
+ *
+ * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK,
+ * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading
+ * child nodes of the specified type.
+ */
+
+mxml_node_t * /* O - First node or NULL if the string has errors. */
+mxmlLoadString(mxml_node_t *top, /* I - Top node */
+ const char *s, /* I - String to load */
+ mxml_load_cb_t cb) /* I - Callback function or MXML_NO_CALLBACK */
+{
+ /*
+ * Read the XML data...
+ */
+
+ return (mxml_load_data(top, (void *)&s, cb, mxml_string_getc, MXML_NO_CALLBACK,
+ NULL));
+}
+
+
+/*
+ * 'mxmlSaveAllocString()' - Save an XML tree to an allocated string.
+ *
+ * This function returns a pointer to a string containing the textual
+ * representation of the XML node tree. The string should be freed
+ * using the free() function when you are done with it. NULL is returned
+ * if the node would produce an empty string or if the string cannot be
+ * allocated.
+ *
+ * The callback argument specifies a function that returns a whitespace
+ * string or NULL before and after each element. If MXML_NO_CALLBACK
+ * is specified, whitespace will only be added before MXML_TEXT nodes
+ * with leading whitespace and before attribute names inside opening
+ * element tags.
+ */
+
+char * /* O - Allocated string or NULL */
+mxmlSaveAllocString(
+ mxml_node_t *node, /* I - Node to write */
+ mxml_save_cb_t cb) /* I - Whitespace callback or MXML_NO_CALLBACK */
+{
+ int bytes; /* Required bytes */
+ char buffer[8192]; /* Temporary buffer */
+ char *s; /* Allocated string */
+
+
+ /*
+ * Write the node to the temporary buffer...
+ */
+
+ bytes = mxmlSaveString(node, buffer, sizeof(buffer), cb);
+
+ if (bytes <= 0)
+ return (NULL);
+
+ if (bytes < (int)(sizeof(buffer) - 1))
+ {
+ /*
+ * Node fit inside the buffer, so just duplicate that string and
+ * return...
+ */
+
+ return (strdup(buffer));
+ }
+
+ /*
+ * Allocate a buffer of the required size and save the node to the
+ * new buffer...
+ */
+
+ if ((s = malloc(bytes + 1)) == NULL)
+ return (NULL);
+
+ mxmlSaveString(node, s, bytes + 1, cb);
+
+ /*
+ * Return the allocated string...
+ */
+
+ return (s);
+}
+
+
+/*
+ * 'mxmlSaveFd()' - Save an XML tree to a file descriptor.
+ *
+ * The callback argument specifies a function that returns a whitespace
+ * string or NULL before and after each element. If MXML_NO_CALLBACK
+ * is specified, whitespace will only be added before MXML_TEXT nodes
+ * with leading whitespace and before attribute names inside opening
+ * element tags.
+ */
+
+int /* O - 0 on success, -1 on error. */
+mxmlSaveFd(mxml_node_t *node, /* I - Node to write */
+ int fd, /* I - File descriptor to write to */
+ mxml_save_cb_t cb) /* I - Whitespace callback or MXML_NO_CALLBACK */
+{
+ int col; /* Final column */
+ _mxml_fdbuf_t buf; /* File descriptor buffer */
+ _mxml_global_t *global = _mxml_global();
+ /* Global data */
+
+
+ /*
+ * Initialize the file descriptor buffer...
+ */
+
+ buf.fd = fd;
+ buf.current = buf.buffer;
+ buf.end = buf.buffer + sizeof(buf.buffer);
+
+ /*
+ * Write the node...
+ */
+
+ if ((col = mxml_write_node(node, &buf, cb, 0, mxml_fd_putc, global)) < 0)
+ return (-1);
+
+ if (col > 0)
+ if (mxml_fd_putc('\n', &buf) < 0)
+ return (-1);
+
+ /*
+ * Flush and return...
+ */
+
+ return (mxml_fd_write(&buf));
+}
+
+
+/*
+ * 'mxmlSaveFile()' - Save an XML tree to a file.
+ *
+ * The callback argument specifies a function that returns a whitespace
+ * string or NULL before and after each element. If MXML_NO_CALLBACK
+ * is specified, whitespace will only be added before MXML_TEXT nodes
+ * with leading whitespace and before attribute names inside opening
+ * element tags.
+ */
+
+int /* O - 0 on success, -1 on error. */
+mxmlSaveFile(mxml_node_t *node, /* I - Node to write */
+ FILE *fp, /* I - File to write to */
+ mxml_save_cb_t cb) /* I - Whitespace callback or MXML_NO_CALLBACK */
+{
+ int col; /* Final column */
+ _mxml_global_t *global = _mxml_global();
+ /* Global data */
+
+
+ /*
+ * Write the node...
+ */
+
+ if ((col = mxml_write_node(node, fp, cb, 0, mxml_file_putc, global)) < 0)
+ return (-1);
+
+ if (col > 0)
+ if (putc('\n', fp) < 0)
+ return (-1);
+
+ /*
+ * Return 0 (success)...
+ */
+
+ return (0);
+}
+
+
+/*
+ * 'mxmlSaveString()' - Save an XML node tree to a string.
+ *
+ * This function returns the total number of bytes that would be
+ * required for the string but only copies (bufsize - 1) characters
+ * into the specified buffer.
+ *
+ * The callback argument specifies a function that returns a whitespace
+ * string or NULL before and after each element. If MXML_NO_CALLBACK
+ * is specified, whitespace will only be added before MXML_TEXT nodes
+ * with leading whitespace and before attribute names inside opening
+ * element tags.
+ */
+
+int /* O - Size of string */
+mxmlSaveString(mxml_node_t *node, /* I - Node to write */
+ char *buffer, /* I - String buffer */
+ int bufsize, /* I - Size of string buffer */
+ mxml_save_cb_t cb) /* I - Whitespace callback or MXML_NO_CALLBACK */
+{
+ int col; /* Final column */
+ char *ptr[2]; /* Pointers for putc_cb */
+ _mxml_global_t *global = _mxml_global();
+ /* Global data */
+
+
+ /*
+ * Write the node...
+ */
+
+ ptr[0] = buffer;
+ ptr[1] = buffer + bufsize;
+
+ if ((col = mxml_write_node(node, ptr, cb, 0, mxml_string_putc, global)) < 0)
+ return (-1);
+
+ if (col > 0)
+ mxml_string_putc('\n', ptr);
+
+ /*
+ * Nul-terminate the buffer...
+ */
+
+ if (ptr[0] >= ptr[1])
+ buffer[bufsize - 1] = '\0';
+ else
+ ptr[0][0] = '\0';
+
+ /*
+ * Return the number of characters...
+ */
+
+ return (ptr[0] - buffer);
+}
+
+
+/*
+ * 'mxmlSAXLoadFd()' - Load a file descriptor into an XML node tree
+ * using a SAX callback.
+ *
+ * The nodes in the specified file are added to the specified top node.
+ * If no top node is provided, the XML file MUST be well-formed with a
+ * single parent node like <?xml> for the entire file. The callback
+ * function returns the value type that should be used for child nodes.
+ * If MXML_NO_CALLBACK is specified then all child nodes will be either
+ * MXML_ELEMENT or MXML_TEXT nodes.
+ *
+ * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK,
+ * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading
+ * child nodes of the specified type.
+ *
+ * The SAX callback must call mxmlRetain() for any nodes that need to
+ * be kept for later use. Otherwise, nodes are deleted when the parent
+ * node is closed or after each data, comment, CDATA, or directive node.
+ *
+ * @since Mini-XML 2.3@
+ */
+
+mxml_node_t * /* O - First node or NULL if the file could not be read. */
+mxmlSAXLoadFd(mxml_node_t *top, /* I - Top node */
+ int fd, /* I - File descriptor to read from */
+ mxml_load_cb_t cb, /* I - Callback function or MXML_NO_CALLBACK */
+ mxml_sax_cb_t sax_cb, /* I - SAX callback or MXML_NO_CALLBACK */
+ void *sax_data) /* I - SAX user data */
+{
+ _mxml_fdbuf_t buf; /* File descriptor buffer */
+
+
+ /*
+ * Initialize the file descriptor buffer...
+ */
+
+ buf.fd = fd;
+ buf.current = buf.buffer;
+ buf.end = buf.buffer;
+
+ /*
+ * Read the XML data...
+ */
+
+ return (mxml_load_data(top, &buf, cb, mxml_fd_getc, sax_cb, sax_data));
+}
+
+
+/*
+ * 'mxmlSAXLoadFile()' - Load a file into an XML node tree
+ * using a SAX callback.
+ *
+ * The nodes in the specified file are added to the specified top node.
+ * If no top node is provided, the XML file MUST be well-formed with a
+ * single parent node like <?xml> for the entire file. The callback
+ * function returns the value type that should be used for child nodes.
+ * If MXML_NO_CALLBACK is specified then all child nodes will be either
+ * MXML_ELEMENT or MXML_TEXT nodes.
+ *
+ * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK,
+ * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading
+ * child nodes of the specified type.
+ *
+ * The SAX callback must call mxmlRetain() for any nodes that need to
+ * be kept for later use. Otherwise, nodes are deleted when the parent
+ * node is closed or after each data, comment, CDATA, or directive node.
+ *
+ * @since Mini-XML 2.3@
+ */
+
+mxml_node_t * /* O - First node or NULL if the file could not be read. */
+mxmlSAXLoadFile(
+ mxml_node_t *top, /* I - Top node */
+ FILE *fp, /* I - File to read from */
+ mxml_load_cb_t cb, /* I - Callback function or MXML_NO_CALLBACK */
+ mxml_sax_cb_t sax_cb, /* I - SAX callback or MXML_NO_CALLBACK */
+ void *sax_data) /* I - SAX user data */
+{
+ /*
+ * Read the XML data...
+ */
+
+ return (mxml_load_data(top, fp, cb, mxml_file_getc, sax_cb, sax_data));
+}
+
+
+/*
+ * 'mxmlSAXLoadString()' - Load a string into an XML node tree
+ * using a SAX callback.
+ *
+ * The nodes in the specified string are added to the specified top node.
+ * If no top node is provided, the XML string MUST be well-formed with a
+ * single parent node like <?xml> for the entire string. The callback
+ * function returns the value type that should be used for child nodes.
+ * If MXML_NO_CALLBACK is specified then all child nodes will be either
+ * MXML_ELEMENT or MXML_TEXT nodes.
+ *
+ * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK,
+ * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading
+ * child nodes of the specified type.
+ *
+ * The SAX callback must call mxmlRetain() for any nodes that need to
+ * be kept for later use. Otherwise, nodes are deleted when the parent
+ * node is closed or after each data, comment, CDATA, or directive node.
+ *
+ * @since Mini-XML 2.3@
+ */
+
+mxml_node_t * /* O - First node or NULL if the string has errors. */
+mxmlSAXLoadString(
+ mxml_node_t *top, /* I - Top node */
+ const char *s, /* I - String to load */
+ mxml_load_cb_t cb, /* I - Callback function or MXML_NO_CALLBACK */
+ mxml_sax_cb_t sax_cb, /* I - SAX callback or MXML_NO_CALLBACK */
+ void *sax_data) /* I - SAX user data */
+{
+ /*
+ * Read the XML data...
+ */
+
+ return (mxml_load_data(top, (void *)&s, cb, mxml_string_getc, sax_cb, sax_data));
+}
+
+
+/*
+ * 'mxmlSetCustomHandlers()' - Set the handling functions for custom data.
+ *
+ * The load function accepts a node pointer and a data string and must
+ * return 0 on success and non-zero on error.
+ *
+ * The save function accepts a node pointer and must return a malloc'd
+ * string on success and NULL on error.
+ *
+ */
+
+void
+mxmlSetCustomHandlers(
+ mxml_custom_load_cb_t load, /* I - Load function */
+ mxml_custom_save_cb_t save) /* I - Save function */
+{
+ _mxml_global_t *global = _mxml_global();
+ /* Global data */
+
+
+ global->custom_load_cb = load;
+ global->custom_save_cb = save;
+}
+
+
+/*
+ * 'mxmlSetErrorCallback()' - Set the error message callback.
+ */
+
+void
+mxmlSetErrorCallback(mxml_error_cb_t cb)/* I - Error callback function */
+{
+ _mxml_global_t *global = _mxml_global();
+ /* Global data */
+
+
+ global->error_cb = cb;
+}
+
+
+/*
+ * 'mxmlSetWrapMargin()' - Set the wrap margin when saving XML data.
+ *
+ * Wrapping is disabled when "column" is 0.
+ *
+ * @since Mini-XML 2.3@
+ */
+
+void
+mxmlSetWrapMargin(int column) /* I - Column for wrapping, 0 to disable wrapping */
+{
+ _mxml_global_t *global = _mxml_global();
+ /* Global data */
+
+
+ global->wrap = column;
+}
+
+
+/*
+ * 'mxml_add_char()' - Add a character to a buffer, expanding as needed.
+ */
+
+static int /* O - 0 on success, -1 on error */
+mxml_add_char(int ch, /* I - Character to add */
+ char **bufptr, /* IO - Current position in buffer */
+ char **buffer, /* IO - Current buffer */
+ int *bufsize) /* IO - Current buffer size */
+{
+ char *newbuffer; /* New buffer value */
+
+
+ if (*bufptr >= (*buffer + *bufsize - 4))
+ {
+ /*
+ * Increase the size of the buffer...
+ */
+
+ if (*bufsize < 1024)
+ (*bufsize) *= 2;
+ else
+ (*bufsize) += 1024;
+
+ if ((newbuffer = realloc(*buffer, *bufsize)) == NULL)
+ {
+ free(*buffer);
+
+ mxml_error("Unable to expand string buffer to %d bytes!", *bufsize);
+
+ return (-1);
+ }
+
+ *bufptr = newbuffer + (*bufptr - *buffer);
+ *buffer = newbuffer;
+ }
+
+ if (ch < 0x80)
+ {
+ /*
+ * Single byte ASCII...
+ */
+
+ *(*bufptr)++ = ch;
+ }
+ else if (ch < 0x800)
+ {
+ /*
+ * Two-byte UTF-8...
+ */
+
+ *(*bufptr)++ = 0xc0 | (ch >> 6);
+ *(*bufptr)++ = 0x80 | (ch & 0x3f);
+ }
+ else if (ch < 0x10000)
+ {
+ /*
+ * Three-byte UTF-8...
+ */
+
+ *(*bufptr)++ = 0xe0 | (ch >> 12);
+ *(*bufptr)++ = 0x80 | ((ch >> 6) & 0x3f);
+ *(*bufptr)++ = 0x80 | (ch & 0x3f);
+ }
+ else
+ {
+ /*
+ * Four-byte UTF-8...
+ */
+
+ *(*bufptr)++ = 0xf0 | (ch >> 18);
+ *(*bufptr)++ = 0x80 | ((ch >> 12) & 0x3f);
+ *(*bufptr)++ = 0x80 | ((ch >> 6) & 0x3f);
+ *(*bufptr)++ = 0x80 | (ch & 0x3f);
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'mxml_fd_getc()' - Read a character from a file descriptor.
+ */
+
+static int /* O - Character or EOF */
+mxml_fd_getc(void *p, /* I - File descriptor buffer */
+ int *encoding) /* IO - Encoding */
+{
+ _mxml_fdbuf_t *buf; /* File descriptor buffer */
+ int ch, /* Current character */
+ temp; /* Temporary character */
+
+
+ /*
+ * Grab the next character in the buffer...
+ */
+
+ buf = (_mxml_fdbuf_t *)p;
+
+ if (buf->current >= buf->end)
+ if (mxml_fd_read(buf) < 0)
+ return (EOF);
+
+ ch = *(buf->current)++;
+
+ switch (*encoding)
+ {
+ case ENCODE_UTF8 :
+ /*
+ * Got a UTF-8 character; convert UTF-8 to Unicode and return...
+ */
+
+ if (!(ch & 0x80))
+ {
+#if DEBUG > 1
+ printf("mxml_fd_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
+#endif /* DEBUG > 1 */
+
+ if (mxml_bad_char(ch))
+ {
+ mxml_error("Bad control character 0x%02x not allowed by XML standard!",
+ ch);
+ return (EOF);
+ }
+
+ return (ch);
+ }
+ else if (ch == 0xfe)
+ {
+ /*
+ * UTF-16 big-endian BOM?
+ */
+
+ if (buf->current >= buf->end)
+ if (mxml_fd_read(buf) < 0)
+ return (EOF);
+
+ ch = *(buf->current)++;
+
+ if (ch != 0xff)
+ return (EOF);
+
+ *encoding = ENCODE_UTF16BE;
+
+ return (mxml_fd_getc(p, encoding));
+ }
+ else if (ch == 0xff)
+ {
+ /*
+ * UTF-16 little-endian BOM?
+ */
+
+ if (buf->current >= buf->end)
+ if (mxml_fd_read(buf) < 0)
+ return (EOF);
+
+ ch = *(buf->current)++;
+
+ if (ch != 0xfe)
+ return (EOF);
+
+ *encoding = ENCODE_UTF16LE;
+
+ return (mxml_fd_getc(p, encoding));
+ }
+ else if ((ch & 0xe0) == 0xc0)
+ {
+ /*
+ * Two-byte value...
+ */
+
+ if (buf->current >= buf->end)
+ if (mxml_fd_read(buf) < 0)
+ return (EOF);
+
+ temp = *(buf->current)++;
+
+ if ((temp & 0xc0) != 0x80)
+ return (EOF);
+
+ ch = ((ch & 0x1f) << 6) | (temp & 0x3f);
+
+ if (ch < 0x80)
+ {
+ mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch);
+ return (EOF);
+ }
+ }
+ else if ((ch & 0xf0) == 0xe0)
+ {
+ /*
+ * Three-byte value...
+ */
+
+ if (buf->current >= buf->end)
+ if (mxml_fd_read(buf) < 0)
+ return (EOF);
+
+ temp = *(buf->current)++;
+
+ if ((temp & 0xc0) != 0x80)
+ return (EOF);
+
+ ch = ((ch & 0x0f) << 6) | (temp & 0x3f);
+
+ if (buf->current >= buf->end)
+ if (mxml_fd_read(buf) < 0)
+ return (EOF);
+
+ temp = *(buf->current)++;
+
+ if ((temp & 0xc0) != 0x80)
+ return (EOF);
+
+ ch = (ch << 6) | (temp & 0x3f);
+
+ if (ch < 0x800)
+ {
+ mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch);
+ return (EOF);
+ }
+
+ /*
+ * Ignore (strip) Byte Order Mark (BOM)...
+ */
+
+ if (ch == 0xfeff)
+ return (mxml_fd_getc(p, encoding));
+ }
+ else if ((ch & 0xf8) == 0xf0)
+ {
+ /*
+ * Four-byte value...
+ */
+
+ if (buf->current >= buf->end)
+ if (mxml_fd_read(buf) < 0)
+ return (EOF);
+
+ temp = *(buf->current)++;
+
+ if ((temp & 0xc0) != 0x80)
+ return (EOF);
+
+ ch = ((ch & 0x07) << 6) | (temp & 0x3f);
+
+ if (buf->current >= buf->end)
+ if (mxml_fd_read(buf) < 0)
+ return (EOF);
+
+ temp = *(buf->current)++;
+
+ if ((temp & 0xc0) != 0x80)
+ return (EOF);
+
+ ch = (ch << 6) | (temp & 0x3f);
+
+ if (buf->current >= buf->end)
+ if (mxml_fd_read(buf) < 0)
+ return (EOF);
+
+ temp = *(buf->current)++;
+
+ if ((temp & 0xc0) != 0x80)
+ return (EOF);
+
+ ch = (ch << 6) | (temp & 0x3f);
+
+ if (ch < 0x10000)
+ {
+ mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch);
+ return (EOF);
+ }
+ }
+ else
+ return (EOF);
+ break;
+
+ case ENCODE_UTF16BE :
+ /*
+ * Read UTF-16 big-endian char...
+ */
+
+ if (buf->current >= buf->end)
+ if (mxml_fd_read(buf) < 0)
+ return (EOF);
+
+ temp = *(buf->current)++;
+
+ ch = (ch << 8) | temp;
+
+ if (mxml_bad_char(ch))
+ {
+ mxml_error("Bad control character 0x%02x not allowed by XML standard!",
+ ch);
+ return (EOF);
+ }
+ else if (ch >= 0xd800 && ch <= 0xdbff)
+ {
+ /*
+ * Multi-word UTF-16 char...
+ */
+
+ int lch;
+
+ if (buf->current >= buf->end)
+ if (mxml_fd_read(buf) < 0)
+ return (EOF);
+
+ lch = *(buf->current)++;
+
+ if (buf->current >= buf->end)
+ if (mxml_fd_read(buf) < 0)
+ return (EOF);
+
+ temp = *(buf->current)++;
+
+ lch = (lch << 8) | temp;
+
+ if (lch < 0xdc00 || lch >= 0xdfff)
+ return (EOF);
+
+ ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
+ }
+ break;
+
+ case ENCODE_UTF16LE :
+ /*
+ * Read UTF-16 little-endian char...
+ */
+
+ if (buf->current >= buf->end)
+ if (mxml_fd_read(buf) < 0)
+ return (EOF);
+
+ temp = *(buf->current)++;
+
+ ch |= (temp << 8);
+
+ if (mxml_bad_char(ch))
+ {
+ mxml_error("Bad control character 0x%02x not allowed by XML standard!",
+ ch);
+ return (EOF);
+ }
+ else if (ch >= 0xd800 && ch <= 0xdbff)
+ {
+ /*
+ * Multi-word UTF-16 char...
+ */
+
+ int lch;
+
+ if (buf->current >= buf->end)
+ if (mxml_fd_read(buf) < 0)
+ return (EOF);
+
+ lch = *(buf->current)++;
+
+ if (buf->current >= buf->end)
+ if (mxml_fd_read(buf) < 0)
+ return (EOF);
+
+ temp = *(buf->current)++;
+
+ lch |= (temp << 8);
+
+ if (lch < 0xdc00 || lch >= 0xdfff)
+ return (EOF);
+
+ ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
+ }
+ break;
+ }
+
+#if DEBUG > 1
+ printf("mxml_fd_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
+#endif /* DEBUG > 1 */
+
+ return (ch);
+}
+
+
+/*
+ * 'mxml_fd_putc()' - Write a character to a file descriptor.
+ */
+
+static int /* O - 0 on success, -1 on error */
+mxml_fd_putc(int ch, /* I - Character */
+ void *p) /* I - File descriptor buffer */
+{
+ _mxml_fdbuf_t *buf; /* File descriptor buffer */
+
+
+ /*
+ * Flush the write buffer as needed...
+ */
+
+ buf = (_mxml_fdbuf_t *)p;
+
+ if (buf->current >= buf->end)
+ if (mxml_fd_write(buf) < 0)
+ return (-1);
+
+ *(buf->current)++ = ch;
+
+ /*
+ * Return successfully...
+ */
+
+ return (0);
+}
+
+
+/*
+ * 'mxml_fd_read()' - Read a buffer of data from a file descriptor.
+ */
+
+static int /* O - 0 on success, -1 on error */
+mxml_fd_read(_mxml_fdbuf_t *buf) /* I - File descriptor buffer */
+{
+ int bytes; /* Bytes read... */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!buf)
+ return (-1);
+
+ /*
+ * Read from the file descriptor...
+ */
+
+ while ((bytes = read(buf->fd, buf->buffer, sizeof(buf->buffer))) < 0)
+#ifdef EINTR
+ if (errno != EAGAIN && errno != EINTR)
+#else
+ if (errno != EAGAIN)
+#endif /* EINTR */
+ return (-1);
+
+ if (bytes == 0)
+ return (-1);
+
+ /*
+ * Update the pointers and return success...
+ */
+
+ buf->current = buf->buffer;
+ buf->end = buf->buffer + bytes;
+
+ return (0);
+}
+
+
+/*
+ * 'mxml_fd_write()' - Write a buffer of data to a file descriptor.
+ */
+
+static int /* O - 0 on success, -1 on error */
+mxml_fd_write(_mxml_fdbuf_t *buf) /* I - File descriptor buffer */
+{
+ int bytes; /* Bytes written */
+ unsigned char *ptr; /* Pointer into buffer */
+
+
+ /*
+ * Range check...
+ */
+
+ if (!buf)
+ return (-1);
+
+ /*
+ * Return 0 if there is nothing to write...
+ */
+
+ if (buf->current == buf->buffer)
+ return (0);
+
+ /*
+ * Loop until we have written everything...
+ */
+
+ for (ptr = buf->buffer; ptr < buf->current; ptr += bytes)
+ if ((bytes = write(buf->fd, ptr, buf->current - ptr)) < 0)
+ return (-1);
+
+ /*
+ * All done, reset pointers and return success...
+ */
+
+ buf->current = buf->buffer;
+
+ return (0);
+}
+
+
+/*
+ * 'mxml_file_getc()' - Get a character from a file.
+ */
+
+static int /* O - Character or EOF */
+mxml_file_getc(void *p, /* I - Pointer to file */
+ int *encoding) /* IO - Encoding */
+{
+ int ch, /* Character from file */
+ temp; /* Temporary character */
+ FILE *fp; /* Pointer to file */
+
+
+ /*
+ * Read a character from the file and see if it is EOF or ASCII...
+ */
+
+ fp = (FILE *)p;
+ ch = getc(fp);
+
+ if (ch == EOF)
+ return (EOF);
+
+ switch (*encoding)
+ {
+ case ENCODE_UTF8 :
+ /*
+ * Got a UTF-8 character; convert UTF-8 to Unicode and return...
+ */
+
+ if (!(ch & 0x80))
+ {
+ if (mxml_bad_char(ch))
+ {
+ mxml_error("Bad control character 0x%02x not allowed by XML standard!",
+ ch);
+ return (EOF);
+ }
+
+#if DEBUG > 1
+ printf("mxml_file_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
+#endif /* DEBUG > 1 */
+
+ return (ch);
+ }
+ else if (ch == 0xfe)
+ {
+ /*
+ * UTF-16 big-endian BOM?
+ */
+
+ ch = getc(fp);
+ if (ch != 0xff)
+ return (EOF);
+
+ *encoding = ENCODE_UTF16BE;
+
+ return (mxml_file_getc(p, encoding));
+ }
+ else if (ch == 0xff)
+ {
+ /*
+ * UTF-16 little-endian BOM?
+ */
+
+ ch = getc(fp);
+ if (ch != 0xfe)
+ return (EOF);
+
+ *encoding = ENCODE_UTF16LE;
+
+ return (mxml_file_getc(p, encoding));
+ }
+ else if ((ch & 0xe0) == 0xc0)
+ {
+ /*
+ * Two-byte value...
+ */
+
+ if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80)
+ return (EOF);
+
+ ch = ((ch & 0x1f) << 6) | (temp & 0x3f);
+
+ if (ch < 0x80)
+ {
+ mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch);
+ return (EOF);
+ }
+ }
+ else if ((ch & 0xf0) == 0xe0)
+ {
+ /*
+ * Three-byte value...
+ */
+
+ if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80)
+ return (EOF);
+
+ ch = ((ch & 0x0f) << 6) | (temp & 0x3f);
+
+ if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80)
+ return (EOF);
+
+ ch = (ch << 6) | (temp & 0x3f);
+
+ if (ch < 0x800)
+ {
+ mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch);
+ return (EOF);
+ }
+
+ /*
+ * Ignore (strip) Byte Order Mark (BOM)...
+ */
+
+ if (ch == 0xfeff)
+ return (mxml_file_getc(p, encoding));
+ }
+ else if ((ch & 0xf8) == 0xf0)
+ {
+ /*
+ * Four-byte value...
+ */
+
+ if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80)
+ return (EOF);
+
+ ch = ((ch & 0x07) << 6) | (temp & 0x3f);
+
+ if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80)
+ return (EOF);
+
+ ch = (ch << 6) | (temp & 0x3f);
+
+ if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80)
+ return (EOF);
+
+ ch = (ch << 6) | (temp & 0x3f);
+
+ if (ch < 0x10000)
+ {
+ mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch);
+ return (EOF);
+ }
+ }
+ else
+ return (EOF);
+ break;
+
+ case ENCODE_UTF16BE :
+ /*
+ * Read UTF-16 big-endian char...
+ */
+
+ ch = (ch << 8) | getc(fp);
+
+ if (mxml_bad_char(ch))
+ {
+ mxml_error("Bad control character 0x%02x not allowed by XML standard!",
+ ch);
+ return (EOF);
+ }
+ else if (ch >= 0xd800 && ch <= 0xdbff)
+ {
+ /*
+ * Multi-word UTF-16 char...
+ */
+
+ int lch = getc(fp);
+ lch = (lch << 8) | getc(fp);
+
+ if (lch < 0xdc00 || lch >= 0xdfff)
+ return (EOF);
+
+ ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
+ }
+ break;
+
+ case ENCODE_UTF16LE :
+ /*
+ * Read UTF-16 little-endian char...
+ */
+
+ ch |= (getc(fp) << 8);
+
+ if (mxml_bad_char(ch))
+ {
+ mxml_error("Bad control character 0x%02x not allowed by XML standard!",
+ ch);
+ return (EOF);
+ }
+ else if (ch >= 0xd800 && ch <= 0xdbff)
+ {
+ /*
+ * Multi-word UTF-16 char...
+ */
+
+ int lch = getc(fp);
+ lch |= (getc(fp) << 8);
+
+ if (lch < 0xdc00 || lch >= 0xdfff)
+ return (EOF);
+
+ ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
+ }
+ break;
+ }
+
+#if DEBUG > 1
+ printf("mxml_file_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
+#endif /* DEBUG > 1 */
+
+ return (ch);
+}
+
+
+/*
+ * 'mxml_file_putc()' - Write a character to a file.
+ */
+
+static int /* O - 0 on success, -1 on failure */
+mxml_file_putc(int ch, /* I - Character to write */
+ void *p) /* I - Pointer to file */
+{
+ return (putc(ch, (FILE *)p) == EOF ? -1 : 0);
+}
+
+
+/*
+ * 'mxml_get_entity()' - Get the character corresponding to an entity...
+ */
+
+static int /* O - Character value or EOF on error */
+mxml_get_entity(mxml_node_t *parent, /* I - Parent node */
+ void *p, /* I - Pointer to source */
+ int *encoding, /* IO - Character encoding */
+ int (*getc_cb)(void *, int *))
+ /* I - Get character function */
+{
+ int ch; /* Current character */
+ char entity[64], /* Entity string */
+ *entptr; /* Pointer into entity */
+
+
+ entptr = entity;
+
+ while ((ch = (*getc_cb)(p, encoding)) != EOF)
+ if (ch > 126 || (!isalnum(ch) && ch != '#'))
+ break;
+ else if (entptr < (entity + sizeof(entity) - 1))
+ *entptr++ = ch;
+ else
+ {
+ mxml_error("Entity name too long under parent <%s>!",
+ parent ? parent->value.element.name : "null");
+ break;
+ }
+
+ *entptr = '\0';
+
+ if (ch != ';')
+ {
+ mxml_error("Character entity \"%s\" not terminated under parent <%s>!",
+ entity, parent ? parent->value.element.name : "null");
+ return (EOF);
+ }
+
+ if (entity[0] == '#')
+ {
+ if (entity[1] == 'x')
+ ch = strtol(entity + 2, NULL, 16);
+ else
+ ch = strtol(entity + 1, NULL, 10);
+ }
+ else if ((ch = mxmlEntityGetValue(entity)) < 0)
+ mxml_error("Entity name \"%s;\" not supported under parent <%s>!",
+ entity, parent ? parent->value.element.name : "null");
+
+ if (mxml_bad_char(ch))
+ {
+ mxml_error("Bad control character 0x%02x under parent <%s> not allowed by XML standard!",
+ ch, parent ? parent->value.element.name : "null");
+ return (EOF);
+ }
+
+ return (ch);
+}
+
+
+/*
+ * 'mxml_load_data()' - Load data into an XML node tree.
+ */
+
+static mxml_node_t * /* O - First node or NULL if the file could not be read. */
+mxml_load_data(
+ mxml_node_t *top, /* I - Top node */
+ void *p, /* I - Pointer to data */
+ mxml_load_cb_t cb, /* I - Callback function or MXML_NO_CALLBACK */
+ _mxml_getc_cb_t getc_cb, /* I - Read function */
+ mxml_sax_cb_t sax_cb, /* I - SAX callback or MXML_NO_CALLBACK */
+ void *sax_data) /* I - SAX user data */
+{
+ mxml_node_t *node, /* Current node */
+ *first, /* First node added */
+ *parent; /* Current parent node */
+ int ch, /* Character from file */
+ whitespace; /* Non-zero if whitespace seen */
+ char *buffer, /* String buffer */
+ *bufptr; /* Pointer into buffer */
+ int bufsize; /* Size of buffer */
+ mxml_type_t type; /* Current node type */
+ int encoding; /* Character encoding */
+ _mxml_global_t *global = _mxml_global();
+ /* Global data */
+ static const char * const types[] = /* Type strings... */
+ {
+ "MXML_ELEMENT", /* XML element with attributes */
+ "MXML_INTEGER", /* Integer value */
+ "MXML_OPAQUE", /* Opaque string */
+ "MXML_REAL", /* Real value */
+ "MXML_TEXT", /* Text fragment */
+ "MXML_CUSTOM" /* Custom data */
+ };
+
+
+ /*
+ * Read elements and other nodes from the file...
+ */
+
+ if ((buffer = malloc(64)) == NULL)
+ {
+ mxml_error("Unable to allocate string buffer!");
+ return (NULL);
+ }
+
+ bufsize = 64;
+ bufptr = buffer;
+ parent = top;
+ first = NULL;
+ whitespace = 0;
+ encoding = ENCODE_UTF8;
+
+ if (cb && parent)
+ type = (*cb)(parent);
+ else if (parent)
+ type = MXML_TEXT;
+ else
+ type = MXML_IGNORE;
+
+ while ((ch = (*getc_cb)(p, &encoding)) != EOF)
+ {
+ if ((ch == '<' ||
+ (mxml_isspace(ch) && type != MXML_OPAQUE && type != MXML_CUSTOM)) &&
+ bufptr > buffer)
+ {
+ /*
+ * Add a new value node...
+ */
+
+ *bufptr = '\0';
+
+ switch (type)
+ {
+ case MXML_INTEGER :
+ node = mxmlNewInteger(parent, strtol(buffer, &bufptr, 0));
+ break;
+
+ case MXML_OPAQUE :
+ node = mxmlNewOpaque(parent, buffer);
+ break;
+
+ case MXML_REAL :
+ node = mxmlNewReal(parent, strtod(buffer, &bufptr));
+ break;
+
+ case MXML_TEXT :
+ node = mxmlNewText(parent, whitespace, buffer);
+ break;
+
+ case MXML_CUSTOM :
+ if (global->custom_load_cb)
+ {
+ /*
+ * Use the callback to fill in the custom data...
+ */
+
+ node = mxmlNewCustom(parent, NULL, NULL);
+
+ if ((*global->custom_load_cb)(node, buffer))
+ {
+ mxml_error("Bad custom value '%s' in parent <%s>!",
+ buffer, parent ? parent->value.element.name : "null");
+ mxmlDelete(node);
+ node = NULL;
+ }
+ break;
+ }
+
+ default : /* Ignore... */
+ node = NULL;
+ break;
+ }
+
+ if (*bufptr)
+ {
+ /*
+ * Bad integer/real number value...
+ */
+
+ mxml_error("Bad %s value '%s' in parent <%s>!",
+ type == MXML_INTEGER ? "integer" : "real", buffer,
+ parent ? parent->value.element.name : "null");
+ break;
+ }
+
+ bufptr = buffer;
+ whitespace = mxml_isspace(ch) && type == MXML_TEXT;
+
+ if (!node && type != MXML_IGNORE)
+ {
+ /*
+ * Print error and return...
+ */
+
+ mxml_error("Unable to add value node of type %s to parent <%s>!",
+ types[type], parent ? parent->value.element.name : "null");
+ goto error;
+ }
+
+ if (sax_cb)
+ {
+ (*sax_cb)(node, MXML_SAX_DATA, sax_data);
+
+ if (!mxmlRelease(node))
+ node = NULL;
+ }
+
+ if (!first && node)
+ first = node;
+ }
+ else if (mxml_isspace(ch) && type == MXML_TEXT)
+ whitespace = 1;
+
+ /*
+ * Add lone whitespace node if we have an element and existing
+ * whitespace...
+ */
+
+ if (ch == '<' && whitespace && type == MXML_TEXT)
+ {
+ if (parent)
+ {
+ node = mxmlNewText(parent, whitespace, "");
+
+ if (sax_cb)
+ {
+ (*sax_cb)(node, MXML_SAX_DATA, sax_data);
+
+ if (!mxmlRelease(node))
+ node = NULL;
+ }
+
+ if (!first && node)
+ first = node;
+ }
+
+ whitespace = 0;
+ }
+
+ if (ch == '<')
+ {
+ /*
+ * Start of open/close tag...
+ */
+
+ bufptr = buffer;
+
+ while ((ch = (*getc_cb)(p, &encoding)) != EOF)
+ if (mxml_isspace(ch) || ch == '>' || (ch == '/' && bufptr > buffer))
+ break;
+ else if (ch == '<')
+ {
+ mxml_error("Bare < in element!");
+ goto error;
+ }
+ else if (ch == '&')
+ {
+ if ((ch = mxml_get_entity(parent, p, &encoding, getc_cb)) == EOF)
+ goto error;
+
+ if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))
+ goto error;
+ }
+ else if (ch < '0' && ch != '!' && ch != '-' && ch != '.' && ch != '/')
+ goto error;
+ else if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))
+ goto error;
+ else if (((bufptr - buffer) == 1 && buffer[0] == '?') ||
+ ((bufptr - buffer) == 3 && !strncmp(buffer, "!--", 3)) ||
+ ((bufptr - buffer) == 8 && !strncmp(buffer, "![CDATA[", 8)))
+ break;
+
+ *bufptr = '\0';
+
+ if (!strcmp(buffer, "!--"))
+ {
+ /*
+ * Gather rest of comment...
+ */
+
+ while ((ch = (*getc_cb)(p, &encoding)) != EOF)
+ {
+ if (ch == '>' && bufptr > (buffer + 4) &&
+ bufptr[-3] != '-' && bufptr[-2] == '-' && bufptr[-1] == '-')
+ break;
+ else if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))
+ goto error;
+ }
+
+ /*
+ * Error out if we didn't get the whole comment...
+ */
+
+ if (ch != '>')
+ {
+ /*
+ * Print error and return...
+ */
+
+ mxml_error("Early EOF in comment node!");
+ goto error;
+ }
+
+
+ /*
+ * Otherwise add this as an element under the current parent...
+ */
+
+ *bufptr = '\0';
+
+ if (!parent && first)
+ {
+ /*
+ * There can only be one root element!
+ */
+
+ mxml_error("<%s> cannot be a second root node after <%s>",
+ buffer, first->value.element.name);
+ goto error;
+ }
+
+ if ((node = mxmlNewElement(parent, buffer)) == NULL)
+ {
+ /*
+ * Just print error for now...
+ */
+
+ mxml_error("Unable to add comment node to parent <%s>!",
+ parent ? parent->value.element.name : "null");
+ break;
+ }
+
+ if (sax_cb)
+ {
+ (*sax_cb)(node, MXML_SAX_COMMENT, sax_data);
+
+ if (!mxmlRelease(node))
+ node = NULL;
+ }
+
+ if (node && !first)
+ first = node;
+ }
+ else if (!strcmp(buffer, "![CDATA["))
+ {
+ /*
+ * Gather CDATA section...
+ */
+
+ while ((ch = (*getc_cb)(p, &encoding)) != EOF)
+ {
+ if (ch == '>' && !strncmp(bufptr - 2, "]]", 2))
+ break;
+ else if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))
+ goto error;
+ }
+
+ /*
+ * Error out if we didn't get the whole comment...
+ */
+
+ if (ch != '>')
+ {
+ /*
+ * Print error and return...
+ */
+
+ mxml_error("Early EOF in CDATA node!");
+ goto error;
+ }
+
+
+ /*
+ * Otherwise add this as an element under the current parent...
+ */
+
+ *bufptr = '\0';
+
+ if (!parent && first)
+ {
+ /*
+ * There can only be one root element!
+ */
+
+ mxml_error("<%s> cannot be a second root node after <%s>",
+ buffer, first->value.element.name);
+ goto error;
+ }
+
+ if ((node = mxmlNewElement(parent, buffer)) == NULL)
+ {
+ /*
+ * Print error and return...
+ */
+
+ mxml_error("Unable to add CDATA node to parent <%s>!",
+ parent ? parent->value.element.name : "null");
+ goto error;
+ }
+
+ if (sax_cb)
+ {
+ (*sax_cb)(node, MXML_SAX_CDATA, sax_data);
+
+ if (!mxmlRelease(node))
+ node = NULL;
+ }
+
+ if (node && !first)
+ first = node;
+ }
+ else if (buffer[0] == '?')
+ {
+ /*
+ * Gather rest of processing instruction...
+ */
+
+ while ((ch = (*getc_cb)(p, &encoding)) != EOF)
+ {
+ if (ch == '>' && bufptr > buffer && bufptr[-1] == '?')
+ break;
+ else if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))
+ goto error;
+ }
+
+ /*
+ * Error out if we didn't get the whole processing instruction...
+ */
+
+ if (ch != '>')
+ {
+ /*
+ * Print error and return...
+ */
+
+ mxml_error("Early EOF in processing instruction node!");
+ goto error;
+ }
+
+ /*
+ * Otherwise add this as an element under the current parent...
+ */
+
+ *bufptr = '\0';
+
+ if (!parent && first)
+ {
+ /*
+ * There can only be one root element!
+ */
+
+ mxml_error("<%s> cannot be a second root node after <%s>",
+ buffer, first->value.element.name);
+ goto error;
+ }
+
+ if ((node = mxmlNewElement(parent, buffer)) == NULL)
+ {
+ /*
+ * Print error and return...
+ */
+
+ mxml_error("Unable to add processing instruction node to parent <%s>!",
+ parent ? parent->value.element.name : "null");
+ goto error;
+ }
+
+ if (sax_cb)
+ {
+ (*sax_cb)(node, MXML_SAX_DIRECTIVE, sax_data);
+
+ if (!mxmlRelease(node))
+ node = NULL;
+ }
+
+ if (node)
+ {
+ if (!first)
+ first = node;
+
+ if (!parent)
+ {
+ parent = node;
+
+ if (cb)
+ type = (*cb)(parent);
+ else
+ type = MXML_TEXT;
+ }
+ }
+ }
+ else if (buffer[0] == '!')
+ {
+ /*
+ * Gather rest of declaration...
+ */
+
+ do
+ {
+ if (ch == '>')
+ break;
+ else
+ {
+ if (ch == '&')
+ if ((ch = mxml_get_entity(parent, p, &encoding, getc_cb)) == EOF)
+ goto error;
+
+ if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))
+ goto error;
+ }
+ }
+ while ((ch = (*getc_cb)(p, &encoding)) != EOF);
+
+ /*
+ * Error out if we didn't get the whole declaration...
+ */
+
+ if (ch != '>')
+ {
+ /*
+ * Print error and return...
+ */
+
+ mxml_error("Early EOF in declaration node!");
+ goto error;
+ }
+
+ /*
+ * Otherwise add this as an element under the current parent...
+ */
+
+ *bufptr = '\0';
+
+ if (!parent && first)
+ {
+ /*
+ * There can only be one root element!
+ */
+
+ mxml_error("<%s> cannot be a second root node after <%s>",
+ buffer, first->value.element.name);
+ goto error;
+ }
+
+ if ((node = mxmlNewElement(parent, buffer)) == NULL)
+ {
+ /*
+ * Print error and return...
+ */
+
+ mxml_error("Unable to add declaration node to parent <%s>!",
+ parent ? parent->value.element.name : "null");
+ goto error;
+ }
+
+ if (sax_cb)
+ {
+ (*sax_cb)(node, MXML_SAX_DIRECTIVE, sax_data);
+
+ if (!mxmlRelease(node))
+ node = NULL;
+ }
+
+ if (node)
+ {
+ if (!first)
+ first = node;
+
+ if (!parent)
+ {
+ parent = node;
+
+ if (cb)
+ type = (*cb)(parent);
+ else
+ type = MXML_TEXT;
+ }
+ }
+ }
+ else if (buffer[0] == '/')
+ {
+ /*
+ * Handle close tag...
+ */
+
+ if (!parent || strcmp(buffer + 1, parent->value.element.name))
+ {
+ /*
+ * Close tag doesn't match tree; print an error for now...
+ */
+
+ mxml_error("Mismatched close tag <%s> under parent <%s>!",
+ buffer, parent ? parent->value.element.name : "(null)");
+ goto error;
+ }
+
+ /*
+ * Keep reading until we see >...
+ */
+
+ while (ch != '>' && ch != EOF)
+ ch = (*getc_cb)(p, &encoding);
+
+ node = parent;
+ parent = parent->parent;
+
+ if (sax_cb)
+ {
+ (*sax_cb)(node, MXML_SAX_ELEMENT_CLOSE, sax_data);
+
+ if (!mxmlRelease(node) && first == node)
+ first = NULL;
+ }
+
+ /*
+ * Ascend into the parent and set the value type as needed...
+ */
+
+ if (cb && parent)
+ type = (*cb)(parent);
+ }
+ else
+ {
+ /*
+ * Handle open tag...
+ */
+
+ if (!parent && first)
+ {
+ /*
+ * There can only be one root element!
+ */
+
+ mxml_error("<%s> cannot be a second root node after <%s>",
+ buffer, first->value.element.name);
+ goto error;
+ }
+
+ if ((node = mxmlNewElement(parent, buffer)) == NULL)
+ {
+ /*
+ * Just print error for now...
+ */
+
+ mxml_error("Unable to add element node to parent <%s>!",
+ parent ? parent->value.element.name : "null");
+ goto error;
+ }
+
+ if (mxml_isspace(ch))
+ {
+ if ((ch = mxml_parse_element(node, p, &encoding, getc_cb)) == EOF)
+ goto error;
+ }
+ else if (ch == '/')
+ {
+ if ((ch = (*getc_cb)(p, &encoding)) != '>')
+ {
+ mxml_error("Expected > but got '%c' instead for element <%s/>!",
+ ch, buffer);
+ mxmlDelete(node);
+ goto error;
+ }
+
+ ch = '/';
+ }
+
+ if (sax_cb)
+ (*sax_cb)(node, MXML_SAX_ELEMENT_OPEN, sax_data);
+
+ if (!first)
+ first = node;
+
+ if (ch == EOF)
+ break;
+
+ if (ch != '/')
+ {
+ /*
+ * Descend into this node, setting the value type as needed...
+ */
+
+ parent = node;
+
+ if (cb && parent)
+ type = (*cb)(parent);
+ else
+ type = MXML_TEXT;
+ }
+ else if (sax_cb)
+ {
+ (*sax_cb)(node, MXML_SAX_ELEMENT_CLOSE, sax_data);
+
+ if (!mxmlRelease(node) && first == node)
+ first = NULL;
+ }
+ }
+
+ bufptr = buffer;
+ }
+ else if (ch == '&')
+ {
+ /*
+ * Add character entity to current buffer...
+ */
+
+ if ((ch = mxml_get_entity(parent, p, &encoding, getc_cb)) == EOF)
+ goto error;
+
+ if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))
+ goto error;
+ }
+ else if (type == MXML_OPAQUE || type == MXML_CUSTOM || !mxml_isspace(ch))
+ {
+ /*
+ * Add character to current buffer...
+ */
+
+ if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))
+ goto error;
+ }
+ }
+
+ /*
+ * Free the string buffer - we don't need it anymore...
+ */
+
+ free(buffer);
+
+ /*
+ * Find the top element and return it...
+ */
+
+ if (parent)
+ {
+ node = parent;
+
+ while (parent != top && parent->parent)
+ parent = parent->parent;
+
+ if (node != parent)
+ {
+ mxml_error("Missing close tag </%s> under parent <%s>!",
+ node->value.element.name,
+ node->parent ? node->parent->value.element.name : "(null)");
+
+ mxmlDelete(first);
+
+ return (NULL);
+ }
+ }
+
+ if (parent)
+ return (parent);
+ else
+ return (first);
+
+ /*
+ * Common error return...
+ */
+
+error:
+
+ mxmlDelete(first);
+
+ free(buffer);
+
+ return (NULL);
+}
+
+
+/*
+ * 'mxml_parse_element()' - Parse an element for any attributes...
+ */
+
+static int /* O - Terminating character */
+mxml_parse_element(
+ mxml_node_t *node, /* I - Element node */
+ void *p, /* I - Data to read from */
+ int *encoding, /* IO - Encoding */
+ _mxml_getc_cb_t getc_cb) /* I - Data callback */
+{
+ int ch, /* Current character in file */
+ quote; /* Quoting character */
+ char *name, /* Attribute name */
+ *value, /* Attribute value */
+ *ptr; /* Pointer into name/value */
+ int namesize, /* Size of name string */
+ valsize; /* Size of value string */
+
+
+ /*
+ * Initialize the name and value buffers...
+ */
+
+ if ((name = malloc(64)) == NULL)
+ {
+ mxml_error("Unable to allocate memory for name!");
+ return (EOF);
+ }
+
+ namesize = 64;
+
+ if ((value = malloc(64)) == NULL)
+ {
+ free(name);
+ mxml_error("Unable to allocate memory for value!");
+ return (EOF);
+ }
+
+ valsize = 64;
+
+ /*
+ * Loop until we hit a >, /, ?, or EOF...
+ */
+
+ while ((ch = (*getc_cb)(p, encoding)) != EOF)
+ {
+#if DEBUG > 1
+ fprintf(stderr, "parse_element: ch='%c'\n", ch);
+#endif /* DEBUG > 1 */
+
+ /*
+ * Skip leading whitespace...
+ */
+
+ if (mxml_isspace(ch))
+ continue;
+
+ /*
+ * Stop at /, ?, or >...
+ */
+
+ if (ch == '/' || ch == '?')
+ {
+ /*
+ * Grab the > character and print an error if it isn't there...
+ */
+
+ quote = (*getc_cb)(p, encoding);
+
+ if (quote != '>')
+ {
+ mxml_error("Expected '>' after '%c' for element %s, but got '%c'!",
+ ch, node->value.element.name, quote);
+ goto error;
+ }
+
+ break;
+ }
+ else if (ch == '<')
+ {
+ mxml_error("Bare < in element %s!", node->value.element.name);
+ goto error;
+ }
+ else if (ch == '>')
+ break;
+
+ /*
+ * Read the attribute name...
+ */
+
+ name[0] = ch;
+ ptr = name + 1;
+
+ if (ch == '\"' || ch == '\'')
+ {
+ /*
+ * Name is in quotes, so get a quoted string...
+ */
+
+ quote = ch;
+
+ while ((ch = (*getc_cb)(p, encoding)) != EOF)
+ {
+ if (ch == '&')
+ if ((ch = mxml_get_entity(node, p, encoding, getc_cb)) == EOF)
+ goto error;
+
+ if (mxml_add_char(ch, &ptr, &name, &namesize))
+ goto error;
+
+ if (ch == quote)
+ break;
+ }
+ }
+ else
+ {
+ /*
+ * Grab an normal, non-quoted name...
+ */
+
+ while ((ch = (*getc_cb)(p, encoding)) != EOF)
+ if (mxml_isspace(ch) || ch == '=' || ch == '/' || ch == '>' ||
+ ch == '?')
+ break;
+ else
+ {
+ if (ch == '&')
+ if ((ch = mxml_get_entity(node, p, encoding, getc_cb)) == EOF)
+ goto error;
+
+ if (mxml_add_char(ch, &ptr, &name, &namesize))
+ goto error;
+ }
+ }
+
+ *ptr = '\0';
+
+ if (mxmlElementGetAttr(node, name))
+ goto error;
+
+ while (ch != EOF && mxml_isspace(ch))
+ ch = (*getc_cb)(p, encoding);
+
+ if (ch == '=')
+ {
+ /*
+ * Read the attribute value...
+ */
+
+ while ((ch = (*getc_cb)(p, encoding)) != EOF && mxml_isspace(ch));
+
+ if (ch == EOF)
+ {
+ mxml_error("Missing value for attribute '%s' in element %s!",
+ name, node->value.element.name);
+ goto error;
+ }
+
+ if (ch == '\'' || ch == '\"')
+ {
+ /*
+ * Read quoted value...
+ */
+
+ quote = ch;
+ ptr = value;
+
+ while ((ch = (*getc_cb)(p, encoding)) != EOF)
+ if (ch == quote)
+ break;
+ else
+ {
+ if (ch == '&')
+ if ((ch = mxml_get_entity(node, p, encoding, getc_cb)) == EOF)
+ goto error;
+
+ if (mxml_add_char(ch, &ptr, &value, &valsize))
+ goto error;
+ }
+
+ *ptr = '\0';
+ }
+ else
+ {
+ /*
+ * Read unquoted value...
+ */
+
+ value[0] = ch;
+ ptr = value + 1;
+
+ while ((ch = (*getc_cb)(p, encoding)) != EOF)
+ if (mxml_isspace(ch) || ch == '=' || ch == '/' || ch == '>')
+ break;
+ else
+ {
+ if (ch == '&')
+ if ((ch = mxml_get_entity(node, p, encoding, getc_cb)) == EOF)
+ goto error;
+
+ if (mxml_add_char(ch, &ptr, &value, &valsize))
+ goto error;
+ }
+
+ *ptr = '\0';
+ }
+
+ /*
+ * Set the attribute with the given string value...
+ */
+
+ mxmlElementSetAttr(node, name, value);
+ }
+ else
+ {
+ mxml_error("Missing value for attribute '%s' in element %s!",
+ name, node->value.element.name);
+ goto error;
+ }
+
+ /*
+ * Check the end character...
+ */
+
+ if (ch == '/' || ch == '?')
+ {
+ /*
+ * Grab the > character and print an error if it isn't there...
+ */
+
+ quote = (*getc_cb)(p, encoding);
+
+ if (quote != '>')
+ {
+ mxml_error("Expected '>' after '%c' for element %s, but got '%c'!",
+ ch, node->value.element.name, quote);
+ ch = EOF;
+ }
+
+ break;
+ }
+ else if (ch == '>')
+ break;
+ }
+
+ /*
+ * Free the name and value buffers and return...
+ */
+
+ free(name);
+ free(value);
+
+ return (ch);
+
+ /*
+ * Common error return point...
+ */
+
+error:
+
+ free(name);
+ free(value);
+
+ return (EOF);
+}
+
+
+/*
+ * 'mxml_string_getc()' - Get a character from a string.
+ */
+
+static int /* O - Character or EOF */
+mxml_string_getc(void *p, /* I - Pointer to file */
+ int *encoding) /* IO - Encoding */
+{
+ int ch; /* Character */
+ const char **s; /* Pointer to string pointer */
+
+
+ s = (const char **)p;
+
+ if ((ch = (*s)[0] & 255) != 0 || *encoding == ENCODE_UTF16LE)
+ {
+ /*
+ * Got character; convert UTF-8 to integer and return...
+ */
+
+ (*s)++;
+
+ switch (*encoding)
+ {
+ case ENCODE_UTF8 :
+ if (!(ch & 0x80))
+ {
+#if DEBUG > 1
+ printf("mxml_string_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
+#endif /* DEBUG > 1 */
+
+ if (mxml_bad_char(ch))
+ {
+ mxml_error("Bad control character 0x%02x not allowed by XML standard!",
+ ch);
+ return (EOF);
+ }
+
+ return (ch);
+ }
+ else if (ch == 0xfe)
+ {
+ /*
+ * UTF-16 big-endian BOM?
+ */
+
+ if (((*s)[0] & 255) != 0xff)
+ return (EOF);
+
+ *encoding = ENCODE_UTF16BE;
+ (*s)++;
+
+ return (mxml_string_getc(p, encoding));
+ }
+ else if (ch == 0xff)
+ {
+ /*
+ * UTF-16 little-endian BOM?
+ */
+
+ if (((*s)[0] & 255) != 0xfe)
+ return (EOF);
+
+ *encoding = ENCODE_UTF16LE;
+ (*s)++;
+
+ return (mxml_string_getc(p, encoding));
+ }
+ else if ((ch & 0xe0) == 0xc0)
+ {
+ /*
+ * Two-byte value...
+ */
+
+ if (((*s)[0] & 0xc0) != 0x80)
+ return (EOF);
+
+ ch = ((ch & 0x1f) << 6) | ((*s)[0] & 0x3f);
+
+ (*s)++;
+
+ if (ch < 0x80)
+ {
+ mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch);
+ return (EOF);
+ }
+
+#if DEBUG > 1
+ printf("mxml_string_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
+#endif /* DEBUG > 1 */
+
+ return (ch);
+ }
+ else if ((ch & 0xf0) == 0xe0)
+ {
+ /*
+ * Three-byte value...
+ */
+
+ if (((*s)[0] & 0xc0) != 0x80 ||
+ ((*s)[1] & 0xc0) != 0x80)
+ return (EOF);
+
+ ch = ((((ch & 0x0f) << 6) | ((*s)[0] & 0x3f)) << 6) | ((*s)[1] & 0x3f);
+
+ (*s) += 2;
+
+ if (ch < 0x800)
+ {
+ mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch);
+ return (EOF);
+ }
+
+ /*
+ * Ignore (strip) Byte Order Mark (BOM)...
+ */
+
+ if (ch == 0xfeff)
+ return (mxml_string_getc(p, encoding));
+
+#if DEBUG > 1
+ printf("mxml_string_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
+#endif /* DEBUG > 1 */
+
+ return (ch);
+ }
+ else if ((ch & 0xf8) == 0xf0)
+ {
+ /*
+ * Four-byte value...
+ */
+
+ if (((*s)[0] & 0xc0) != 0x80 ||
+ ((*s)[1] & 0xc0) != 0x80 ||
+ ((*s)[2] & 0xc0) != 0x80)
+ return (EOF);
+
+ ch = ((((((ch & 0x07) << 6) | ((*s)[0] & 0x3f)) << 6) |
+ ((*s)[1] & 0x3f)) << 6) | ((*s)[2] & 0x3f);
+
+ (*s) += 3;
+
+ if (ch < 0x10000)
+ {
+ mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch);
+ return (EOF);
+ }
+
+#if DEBUG > 1
+ printf("mxml_string_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
+#endif /* DEBUG > 1 */
+
+ return (ch);
+ }
+ else
+ return (EOF);
+
+ case ENCODE_UTF16BE :
+ /*
+ * Read UTF-16 big-endian char...
+ */
+
+ ch = (ch << 8) | ((*s)[0] & 255);
+ (*s) ++;
+
+ if (mxml_bad_char(ch))
+ {
+ mxml_error("Bad control character 0x%02x not allowed by XML standard!",
+ ch);
+ return (EOF);
+ }
+ else if (ch >= 0xd800 && ch <= 0xdbff)
+ {
+ /*
+ * Multi-word UTF-16 char...
+ */
+
+ int lch; /* Lower word */
+
+
+ if (!(*s)[0])
+ return (EOF);
+
+ lch = (((*s)[0] & 255) << 8) | ((*s)[1] & 255);
+ (*s) += 2;
+
+ if (lch < 0xdc00 || lch >= 0xdfff)
+ return (EOF);
+
+ ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
+ }
+
+#if DEBUG > 1
+ printf("mxml_string_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
+#endif /* DEBUG > 1 */
+
+ return (ch);
+
+ case ENCODE_UTF16LE :
+ /*
+ * Read UTF-16 little-endian char...
+ */
+
+ ch = ch | (((*s)[0] & 255) << 8);
+
+ if (!ch)
+ {
+ (*s) --;
+ return (EOF);
+ }
+
+ (*s) ++;
+
+ if (mxml_bad_char(ch))
+ {
+ mxml_error("Bad control character 0x%02x not allowed by XML standard!",
+ ch);
+ return (EOF);
+ }
+ else if (ch >= 0xd800 && ch <= 0xdbff)
+ {
+ /*
+ * Multi-word UTF-16 char...
+ */
+
+ int lch; /* Lower word */
+
+
+ if (!(*s)[1])
+ return (EOF);
+
+ lch = (((*s)[1] & 255) << 8) | ((*s)[0] & 255);
+ (*s) += 2;
+
+ if (lch < 0xdc00 || lch >= 0xdfff)
+ return (EOF);
+
+ ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
+ }
+
+#if DEBUG > 1
+ printf("mxml_string_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
+#endif /* DEBUG > 1 */
+
+ return (ch);
+ }
+ }
+
+ return (EOF);
+}
+
+
+/*
+ * 'mxml_string_putc()' - Write a character to a string.
+ */
+
+static int /* O - 0 on success, -1 on failure */
+mxml_string_putc(int ch, /* I - Character to write */
+ void *p) /* I - Pointer to string pointers */
+{
+ char **pp; /* Pointer to string pointers */
+
+
+ pp = (char **)p;
+
+ if (pp[0] < pp[1])
+ pp[0][0] = ch;
+
+ pp[0] ++;
+
+ return (0);
+}
+
+
+/*
+ * 'mxml_write_name()' - Write a name string.
+ */
+
+static int /* O - 0 on success, -1 on failure */
+mxml_write_name(const char *s, /* I - Name to write */
+ void *p, /* I - Write pointer */
+ int (*putc_cb)(int, void *))
+ /* I - Write callback */
+{
+ char quote; /* Quote character */
+ const char *name; /* Entity name */
+
+
+ if (*s == '\"' || *s == '\'')
+ {
+ /*
+ * Write a quoted name string...
+ */
+
+ if ((*putc_cb)(*s, p) < 0)
+ return (-1);
+
+ quote = *s++;
+
+ while (*s && *s != quote)
+ {
+ if ((name = mxmlEntityGetName(*s)) != NULL)
+ {
+ if ((*putc_cb)('&', p) < 0)
+ return (-1);
+
+ while (*name)
+ {
+ if ((*putc_cb)(*name, p) < 0)
+ return (-1);
+
+ name ++;
+ }
+
+ if ((*putc_cb)(';', p) < 0)
+ return (-1);
+ }
+ else if ((*putc_cb)(*s, p) < 0)
+ return (-1);
+
+ s ++;
+ }
+
+ /*
+ * Write the end quote...
+ */
+
+ if ((*putc_cb)(quote, p) < 0)
+ return (-1);
+ }
+ else
+ {
+ /*
+ * Write a non-quoted name string...
+ */
+
+ while (*s)
+ {
+ if ((*putc_cb)(*s, p) < 0)
+ return (-1);
+
+ s ++;
+ }
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'mxml_write_node()' - Save an XML node to a file.
+ */
+
+static int /* O - Column or -1 on error */
+mxml_write_node(mxml_node_t *node, /* I - Node to write */
+ void *p, /* I - File to write to */
+ mxml_save_cb_t cb, /* I - Whitespace callback */
+ int col, /* I - Current column */
+ _mxml_putc_cb_t putc_cb,/* I - Output callback */
+ _mxml_global_t *global)/* I - Global data */
+{
+ mxml_node_t *current, /* Current node */
+ *next; /* Next node */
+ int i, /* Looping var */
+ width; /* Width of attr + value */
+ mxml_attr_t *attr; /* Current attribute */
+ char s[255]; /* Temporary string */
+
+
+ /*
+ * Loop through this node and all of its children...
+ */
+
+ for (current = node; current; current = next)
+ {
+ /*
+ * Print the node value...
+ */
+
+ switch (current->type)
+ {
+ case MXML_ELEMENT :
+ col = mxml_write_ws(current, p, cb, MXML_WS_BEFORE_OPEN, col, putc_cb);
+
+ if ((*putc_cb)('<', p) < 0)
+ return (-1);
+ if (current->value.element.name[0] == '?' ||
+ !strncmp(current->value.element.name, "!--", 3) ||
+ !strncmp(current->value.element.name, "![CDATA[", 8))
+ {
+ /*
+ * Comments, CDATA, and processing instructions do not
+ * use character entities.
+ */
+
+ const char *ptr; /* Pointer into name */
+
+ for (ptr = current->value.element.name; *ptr; ptr ++)
+ if ((*putc_cb)(*ptr, p) < 0)
+ return (-1);
+ }
+ else if (mxml_write_name(current->value.element.name, p, putc_cb) < 0)
+ return (-1);
+
+ col += strlen(current->value.element.name) + 1;
+
+ for (i = current->value.element.num_attrs, attr = current->value.element.attrs;
+ i > 0;
+ i --, attr ++)
+ {
+ width = strlen(attr->name);
+
+ if (attr->value)
+ width += strlen(attr->value) + 3;
+
+ if (global->wrap > 0 && (col + width) > global->wrap)
+ {
+ if ((*putc_cb)('\n', p) < 0)
+ return (-1);
+
+ col = 0;
+ }
+ else
+ {
+ if ((*putc_cb)(' ', p) < 0)
+ return (-1);
+
+ col ++;
+ }
+
+ if (mxml_write_name(attr->name, p, putc_cb) < 0)
+ return (-1);
+
+ if (attr->value)
+ {
+ if ((*putc_cb)('=', p) < 0)
+ return (-1);
+ if ((*putc_cb)('\"', p) < 0)
+ return (-1);
+ if (mxml_write_string(attr->value, p, putc_cb) < 0)
+ return (-1);
+ if ((*putc_cb)('\"', p) < 0)
+ return (-1);
+ }
+
+ col += width;
+ }
+
+ if (current->child)
+ {
+ /*
+ * Write children...
+ */
+
+ if ((*putc_cb)('>', p) < 0)
+ return (-1);
+ else
+ col ++;
+
+ col = mxml_write_ws(current, p, cb, MXML_WS_AFTER_OPEN, col, putc_cb);
+ }
+ else if (current->value.element.name[0] == '!' ||
+ current->value.element.name[0] == '?')
+ {
+ /*
+ * The ? and ! elements are special-cases...
+ */
+
+ if ((*putc_cb)('>', p) < 0)
+ return (-1);
+ else
+ col ++;
+
+ col = mxml_write_ws(current, p, cb, MXML_WS_AFTER_OPEN, col, putc_cb);
+ }
+ else
+ {
+ if ((*putc_cb)(' ', p) < 0)
+ return (-1);
+ if ((*putc_cb)('/', p) < 0)
+ return (-1);
+ if ((*putc_cb)('>', p) < 0)
+ return (-1);
+
+ col += 3;
+
+ col = mxml_write_ws(current, p, cb, MXML_WS_AFTER_OPEN, col, putc_cb);
+ }
+ break;
+
+ case MXML_INTEGER :
+ if (current->prev)
+ {
+ if (global->wrap > 0 && col > global->wrap)
+ {
+ if ((*putc_cb)('\n', p) < 0)
+ return (-1);
+
+ col = 0;
+ }
+ else if ((*putc_cb)(' ', p) < 0)
+ return (-1);
+ else
+ col ++;
+ }
+
+ sprintf(s, "%d", current->value.integer);
+ if (mxml_write_string(s, p, putc_cb) < 0)
+ return (-1);
+
+ col += strlen(s);
+ break;
+
+ case MXML_OPAQUE :
+ if (mxml_write_string(current->value.opaque, p, putc_cb) < 0)
+ return (-1);
+
+ col += strlen(current->value.opaque);
+ break;
+
+ case MXML_REAL :
+ if (current->prev)
+ {
+ if (global->wrap > 0 && col > global->wrap)
+ {
+ if ((*putc_cb)('\n', p) < 0)
+ return (-1);
+
+ col = 0;
+ }
+ else if ((*putc_cb)(' ', p) < 0)
+ return (-1);
+ else
+ col ++;
+ }
+
+ sprintf(s, "%f", current->value.real);
+ if (mxml_write_string(s, p, putc_cb) < 0)
+ return (-1);
+
+ col += strlen(s);
+ break;
+
+ case MXML_TEXT :
+ if (current->value.text.whitespace && col > 0)
+ {
+ if (global->wrap > 0 && col > global->wrap)
+ {
+ if ((*putc_cb)('\n', p) < 0)
+ return (-1);
+
+ col = 0;
+ }
+ else if ((*putc_cb)(' ', p) < 0)
+ return (-1);
+ else
+ col ++;
+ }
+
+ if (mxml_write_string(current->value.text.string, p, putc_cb) < 0)
+ return (-1);
+
+ col += strlen(current->value.text.string);
+ break;
+
+ case MXML_CUSTOM :
+ if (global->custom_save_cb)
+ {
+ char *data; /* Custom data string */
+ const char *newline; /* Last newline in string */
+
+
+ if ((data = (*global->custom_save_cb)(node)) == NULL)
+ return (-1);
+
+ if (mxml_write_string(data, p, putc_cb) < 0)
+ return (-1);
+
+ if ((newline = strrchr(data, '\n')) == NULL)
+ col += strlen(data);
+ else
+ col = strlen(newline);
+
+ free(data);
+ break;
+ }
+
+ default : /* Should never happen */
+ return (-1);
+ }
+
+ /*
+ * Figure out the next node...
+ */
+
+ if ((next = current->child) == NULL)
+ {
+ while ((next = current->next) == NULL)
+ {
+ if (current == node)
+ break;
+
+ /*
+ * The ? and ! elements are special-cases and have no end tags...
+ */
+
+ current = current->parent;
+
+ if (current->value.element.name[0] != '!' &&
+ current->value.element.name[0] != '?')
+ {
+ col = mxml_write_ws(current, p, cb, MXML_WS_BEFORE_CLOSE, col, putc_cb);
+
+ if ((*putc_cb)('<', p) < 0)
+ return (-1);
+ if ((*putc_cb)('/', p) < 0)
+ return (-1);
+ if (mxml_write_string(current->value.element.name, p, putc_cb) < 0)
+ return (-1);
+ if ((*putc_cb)('>', p) < 0)
+ return (-1);
+
+ col += strlen(current->value.element.name) + 3;
+
+ col = mxml_write_ws(current, p, cb, MXML_WS_AFTER_CLOSE, col, putc_cb);
+ }
+ }
+ }
+ }
+
+ return (col);
+}
+
+
+/*
+ * 'mxml_write_string()' - Write a string, escaping & and < as needed.
+ */
+
+static int /* O - 0 on success, -1 on failure */
+mxml_write_string(
+ const char *s, /* I - String to write */
+ void *p, /* I - Write pointer */
+ _mxml_putc_cb_t putc_cb) /* I - Write callback */
+{
+ const char *name; /* Entity name, if any */
+
+
+ while (*s)
+ {
+ if ((name = mxmlEntityGetName(*s)) != NULL)
+ {
+ if ((*putc_cb)('&', p) < 0)
+ return (-1);
+
+ while (*name)
+ {
+ if ((*putc_cb)(*name, p) < 0)
+ return (-1);
+ name ++;
+ }
+
+ if ((*putc_cb)(';', p) < 0)
+ return (-1);
+ }
+ else if ((*putc_cb)(*s, p) < 0)
+ return (-1);
+
+ s ++;
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'mxml_write_ws()' - Do whitespace callback...
+ */
+
+static int /* O - New column */
+mxml_write_ws(mxml_node_t *node, /* I - Current node */
+ void *p, /* I - Write pointer */
+ mxml_save_cb_t cb, /* I - Callback function */
+ int ws, /* I - Where value */
+ int col, /* I - Current column */
+ _mxml_putc_cb_t putc_cb) /* I - Write callback */
+{
+ const char *s; /* Whitespace string */
+
+
+ if (cb && (s = (*cb)(node, ws)) != NULL)
+ {
+ while (*s)
+ {
+ if ((*putc_cb)(*s, p) < 0)
+ return (-1);
+ else if (*s == '\n')
+ col = 0;
+ else if (*s == '\t')
+ {
+ col += MXML_TAB;
+ col = col - (col % MXML_TAB);
+ }
+ else
+ col ++;
+
+ s ++;
+ }
+ }
+
+ return (col);
+}
+
+
+/*
+ * End of "$Id: mxml-file.c 467 2016-06-13 00:51:16Z msweet $".
+ */
diff --git a/emb/pastilda/lib/miniXML/mxml-get.c b/emb/pastilda/lib/miniXML/mxml-get.c
new file mode 100644
index 0000000..40ed3d0
--- /dev/null
+++ b/emb/pastilda/lib/miniXML/mxml-get.c
@@ -0,0 +1,452 @@
+/*
+ * "$Id: mxml-get.c 451 2014-01-04 21:50:06Z msweet $"
+ *
+ * Node get functions for Mini-XML, a small XML-like file parsing library.
+ *
+ * Copyright 2014 by Michael R Sweet.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Michael R Sweet and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "COPYING"
+ * which should have been included with this file. If this file is
+ * missing or damaged, see the license at:
+ *
+ * http://www.msweet.org/projects.php/Mini-XML
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "config.h"
+#include "mxml.h"
+
+
+/*
+ * 'mxmlGetCDATA()' - Get the value for a CDATA node.
+ *
+ * @code NULL@ is returned if the node is not a CDATA element.
+ *
+ * @since Mini-XML 2.7@
+ */
+
+const char * /* O - CDATA value or NULL */
+mxmlGetCDATA(mxml_node_t *node) /* I - Node to get */
+{
+ /*
+ * Range check input...
+ */
+
+ if (!node || node->type != MXML_ELEMENT ||
+ strncmp(node->value.element.name, "![CDATA[", 8))
+ return (NULL);
+
+ /*
+ * Return the text following the CDATA declaration...
+ */
+
+ return (node->value.element.name + 8);
+}
+
+
+/*
+ * 'mxmlGetCustom()' - Get the value for a custom node.
+ *
+ * @code NULL@ is returned if the node (or its first child) is not a custom
+ * value node.
+ *
+ * @since Mini-XML 2.7@
+ */
+
+const void * /* O - Custom value or NULL */
+mxmlGetCustom(mxml_node_t *node) /* I - Node to get */
+{
+ /*
+ * Range check input...
+ */
+
+ if (!node)
+ return (NULL);
+
+ /*
+ * Return the integer value...
+ */
+
+ if (node->type == MXML_CUSTOM)
+ return (node->value.custom.data);
+ else if (node->type == MXML_ELEMENT &&
+ node->child &&
+ node->child->type == MXML_CUSTOM)
+ return (node->child->value.custom.data);
+ else
+ return (NULL);
+}
+
+
+/*
+ * 'mxmlGetElement()' - Get the name for an element node.
+ *
+ * @code NULL@ is returned if the node is not an element node.
+ *
+ * @since Mini-XML 2.7@
+ */
+
+const char * /* O - Element name or NULL */
+mxmlGetElement(mxml_node_t *node) /* I - Node to get */
+{
+ /*
+ * Range check input...
+ */
+
+ if (!node || node->type != MXML_ELEMENT)
+ return (NULL);
+
+ /*
+ * Return the element name...
+ */
+
+ return (node->value.element.name);
+}
+
+
+/*
+ * 'mxmlGetFirstChild()' - Get the first child of an element node.
+ *
+ * @code NULL@ is returned if the node is not an element node or if the node
+ * has no children.
+ *
+ * @since Mini-XML 2.7@
+ */
+
+mxml_node_t * /* O - First child or NULL */
+mxmlGetFirstChild(mxml_node_t *node) /* I - Node to get */
+{
+ /*
+ * Range check input...
+ */
+
+ if (!node || node->type != MXML_ELEMENT)
+ return (NULL);
+
+ /*
+ * Return the first child node...
+ */
+
+ return (node->child);
+}
+
+
+/*
+ * 'mxmlGetInteger()' - Get the integer value from the specified node or its
+ * first child.
+ *
+ * 0 is returned if the node (or its first child) is not an integer value node.
+ *
+ * @since Mini-XML 2.7@
+ */
+
+int /* O - Integer value or 0 */
+mxmlGetInteger(mxml_node_t *node) /* I - Node to get */
+{
+ /*
+ * Range check input...
+ */
+
+ if (!node)
+ return (0);
+
+ /*
+ * Return the integer value...
+ */
+
+ if (node->type == MXML_INTEGER)
+ return (node->value.integer);
+ else if (node->type == MXML_ELEMENT &&
+ node->child &&
+ node->child->type == MXML_INTEGER)
+ return (node->child->value.integer);
+ else
+ return (0);
+}
+
+
+/*
+ * 'mxmlGetLastChild()' - Get the last child of an element node.
+ *
+ * @code NULL@ is returned if the node is not an element node or if the node
+ * has no children.
+ *
+ * @since Mini-XML 2.7@
+ */
+
+mxml_node_t * /* O - Last child or NULL */
+mxmlGetLastChild(mxml_node_t *node) /* I - Node to get */
+{
+ /*
+ * Range check input...
+ */
+
+ if (!node || node->type != MXML_ELEMENT)
+ return (NULL);
+
+ /*
+ * Return the node type...
+ */
+
+ return (node->last_child);
+}
+
+
+/*
+ * 'mxmlGetNextSibling()' - Get the next node for the current parent.
+ *
+ * @code NULL@ is returned if this is the last child for the current parent.
+ *
+ * @since Mini-XML 2.7@
+ */
+
+mxml_node_t *
+mxmlGetNextSibling(mxml_node_t *node) /* I - Node to get */
+{
+ /*
+ * Range check input...
+ */
+
+ if (!node)
+ return (NULL);
+
+ /*
+ * Return the node type...
+ */
+
+ return (node->next);
+}
+
+
+/*
+ * 'mxmlGetOpaque()' - Get an opaque string value for a node or its first child.
+ *
+ * @code NULL@ is returned if the node (or its first child) is not an opaque
+ * value node.
+ *
+ * @since Mini-XML 2.7@
+ */
+
+const char * /* O - Opaque string or NULL */
+mxmlGetOpaque(mxml_node_t *node) /* I - Node to get */
+{
+ /*
+ * Range check input...
+ */
+
+ if (!node)
+ return (NULL);
+
+ /*
+ * Return the integer value...
+ */
+
+ if (node->type == MXML_OPAQUE)
+ return (node->value.opaque);
+ else if (node->type == MXML_ELEMENT &&
+ node->child &&
+ node->child->type == MXML_OPAQUE)
+ return (node->child->value.opaque);
+ else
+ return (NULL);
+}
+
+
+/*
+ * 'mxmlGetParent()' - Get the parent node.
+ *
+ * @code NULL@ is returned for a root node.
+ *
+ * @since Mini-XML 2.7@
+ */
+
+mxml_node_t * /* O - Parent node or NULL */
+mxmlGetParent(mxml_node_t *node) /* I - Node to get */
+{
+ /*
+ * Range check input...
+ */
+
+ if (!node)
+ return (NULL);
+
+ /*
+ * Return the node type...
+ */
+
+ return (node->parent);
+}
+
+
+/*
+ * 'mxmlGetPrevSibling()' - Get the previous node for the current parent.
+ *
+ * @code NULL@ is returned if this is the first child for the current parent.
+ *
+ * @since Mini-XML 2.7@
+ */
+
+mxml_node_t * /* O - Previous node or NULL */
+mxmlGetPrevSibling(mxml_node_t *node) /* I - Node to get */
+{
+ /*
+ * Range check input...
+ */
+
+ if (!node)
+ return (NULL);
+
+ /*
+ * Return the node type...
+ */
+
+ return (node->prev);
+}
+
+
+/*
+ * 'mxmlGetReal()' - Get the real value for a node or its first child.
+ *
+ * 0.0 is returned if the node (or its first child) is not a real value node.
+ *
+ * @since Mini-XML 2.7@
+ */
+
+double /* O - Real value or 0.0 */
+mxmlGetReal(mxml_node_t *node) /* I - Node to get */
+{
+ /*
+ * Range check input...
+ */
+
+ if (!node)
+ return (0.0);
+
+ /*
+ * Return the integer value...
+ */
+
+ if (node->type == MXML_REAL)
+ return (node->value.real);
+ else if (node->type == MXML_ELEMENT &&
+ node->child &&
+ node->child->type == MXML_REAL)
+ return (node->child->value.real);
+ else
+ return (0.0);
+}
+
+
+/*
+ * 'mxmlGetText()' - Get the text value for a node or its first child.
+ *
+ * @code NULL@ is returned if the node (or its first child) is not a text node.
+ * The "whitespace" argument can be NULL.
+ *
+ * @since Mini-XML 2.7@
+ */
+
+const char * /* O - Text string or NULL */
+mxmlGetText(mxml_node_t *node, /* I - Node to get */
+ int *whitespace) /* O - 1 if string is preceded by whitespace, 0 otherwise */
+{
+ /*
+ * Range check input...
+ */
+
+ if (!node)
+ {
+ if (whitespace)
+ *whitespace = 0;
+
+ return (NULL);
+ }
+
+ /*
+ * Return the integer value...
+ */
+
+ if (node->type == MXML_TEXT)
+ {
+ if (whitespace)
+ *whitespace = node->value.text.whitespace;
+
+ return (node->value.text.string);
+ }
+ else if (node->type == MXML_ELEMENT &&
+ node->child &&
+ node->child->type == MXML_TEXT)
+ {
+ if (whitespace)
+ *whitespace = node->child->value.text.whitespace;
+
+ return (node->child->value.text.string);
+ }
+ else
+ {
+ if (whitespace)
+ *whitespace = 0;
+
+ return (NULL);
+ }
+}
+
+
+/*
+ * 'mxmlGetType()' - Get the node type.
+ *
+ * @code MXML_IGNORE@ is returned if "node" is @code NULL@.
+ *
+ * @since Mini-XML 2.7@
+ */
+
+mxml_type_t /* O - Type of node */
+mxmlGetType(mxml_node_t *node) /* I - Node to get */
+{
+ /*
+ * Range check input...
+ */
+
+ if (!node)
+ return (MXML_IGNORE);
+
+ /*
+ * Return the node type...
+ */
+
+ return (node->type);
+}
+
+
+/*
+ * 'mxmlGetUserData()' - Get the user data pointer for a node.
+ *
+ * @since Mini-XML 2.7@
+ */
+
+void * /* O - User data pointer */
+mxmlGetUserData(mxml_node_t *node) /* I - Node to get */
+{
+ /*
+ * Range check input...
+ */
+
+ if (!node)
+ return (NULL);
+
+ /*
+ * Return the user data pointer...
+ */
+
+ return (node->user_data);
+}
+
+
+/*
+ * End of "$Id: mxml-get.c 451 2014-01-04 21:50:06Z msweet $".
+ */
diff --git a/emb/pastilda/lib/miniXML/mxml-index.c b/emb/pastilda/lib/miniXML/mxml-index.c
new file mode 100644
index 0000000..1081439
--- /dev/null
+++ b/emb/pastilda/lib/miniXML/mxml-index.c
@@ -0,0 +1,659 @@
+/*
+ * "$Id: mxml-index.c 451 2014-01-04 21:50:06Z msweet $"
+ *
+ * Index support code for Mini-XML, a small XML-like file parsing library.
+ *
+ * Copyright 2003-2014 by Michael R Sweet.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Michael R Sweet and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "COPYING"
+ * which should have been included with this file. If this file is
+ * missing or damaged, see the license at:
+ *
+ * http://www.msweet.org/projects.php/Mini-XML
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "config.h"
+#include "mxml.h"
+
+
+/*
+ * Sort functions...
+ */
+
+static int index_compare(mxml_index_t *ind, mxml_node_t *first,
+ mxml_node_t *second);
+static int index_find(mxml_index_t *ind, const char *element,
+ const char *value, mxml_node_t *node);
+static void index_sort(mxml_index_t *ind, int left, int right);
+
+
+/*
+ * 'mxmlIndexDelete()' - Delete an index.
+ */
+
+void
+mxmlIndexDelete(mxml_index_t *ind) /* I - Index to delete */
+{
+ /*
+ * Range check input..
+ */
+
+ if (!ind)
+ return;
+
+ /*
+ * Free memory...
+ */
+
+ if (ind->attr)
+ free(ind->attr);
+
+ if (ind->alloc_nodes)
+ free(ind->nodes);
+
+ free(ind);
+}
+
+
+/*
+ * 'mxmlIndexEnum()' - Return the next node in the index.
+ *
+ * Nodes are returned in the sorted order of the index.
+ */
+
+mxml_node_t * /* O - Next node or NULL if there is none */
+mxmlIndexEnum(mxml_index_t *ind) /* I - Index to enumerate */
+{
+ /*
+ * Range check input...
+ */
+
+ if (!ind)
+ return (NULL);
+
+ /*
+ * Return the next node...
+ */
+
+ if (ind->cur_node < ind->num_nodes)
+ return (ind->nodes[ind->cur_node ++]);
+ else
+ return (NULL);
+}
+
+
+/*
+ * 'mxmlIndexFind()' - Find the next matching node.
+ *
+ * You should call mxmlIndexReset() prior to using this function for
+ * the first time with a particular set of "element" and "value"
+ * strings. Passing NULL for both "element" and "value" is equivalent
+ * to calling mxmlIndexEnum().
+ */
+
+mxml_node_t * /* O - Node or NULL if none found */
+mxmlIndexFind(mxml_index_t *ind, /* I - Index to search */
+ const char *element, /* I - Element name to find, if any */
+ const char *value) /* I - Attribute value, if any */
+{
+ int diff, /* Difference between names */
+ current, /* Current entity in search */
+ first, /* First entity in search */
+ last; /* Last entity in search */
+
+
+#ifdef DEBUG
+ printf("mxmlIndexFind(ind=%p, element=\"%s\", value=\"%s\")\n",
+ ind, element ? element : "(null)", value ? value : "(null)");
+#endif /* DEBUG */
+
+ /*
+ * Range check input...
+ */
+
+ if (!ind || (!ind->attr && value))
+ {
+#ifdef DEBUG
+ puts(" returning NULL...");
+ printf(" ind->attr=\"%s\"\n", ind->attr ? ind->attr : "(null)");
+#endif /* DEBUG */
+
+ return (NULL);
+ }
+
+ /*
+ * If both element and value are NULL, just enumerate the nodes in the
+ * index...
+ */
+
+ if (!element && !value)
+ return (mxmlIndexEnum(ind));
+
+ /*
+ * If there are no nodes in the index, return NULL...
+ */
+
+ if (!ind->num_nodes)
+ {
+#ifdef DEBUG
+ puts(" returning NULL...");
+ puts(" no nodes!");
+#endif /* DEBUG */
+
+ return (NULL);
+ }
+
+ /*
+ * If cur_node == 0, then find the first matching node...
+ */
+
+ if (ind->cur_node == 0)
+ {
+ /*
+ * Find the first node using a modified binary search algorithm...
+ */
+
+ first = 0;
+ last = ind->num_nodes - 1;
+
+#ifdef DEBUG
+ printf(" find first time, num_nodes=%d...\n", ind->num_nodes);
+#endif /* DEBUG */
+
+ while ((last - first) > 1)
+ {
+ current = (first + last) / 2;
+
+#ifdef DEBUG
+ printf(" first=%d, last=%d, current=%d\n", first, last, current);
+#endif /* DEBUG */
+
+ if ((diff = index_find(ind, element, value, ind->nodes[current])) == 0)
+ {
+ /*
+ * Found a match, move back to find the first...
+ */
+
+#ifdef DEBUG
+ puts(" match!");
+#endif /* DEBUG */
+
+ while (current > 0 &&
+ !index_find(ind, element, value, ind->nodes[current - 1]))
+ current --;
+
+#ifdef DEBUG
+ printf(" returning first match=%d\n", current);
+#endif /* DEBUG */
+
+ /*
+ * Return the first match and save the index to the next...
+ */
+
+ ind->cur_node = current + 1;
+
+ return (ind->nodes[current]);
+ }
+ else if (diff < 0)
+ last = current;
+ else
+ first = current;
+
+#ifdef DEBUG
+ printf(" diff=%d\n", diff);
+#endif /* DEBUG */
+ }
+
+ /*
+ * If we get this far, then we found exactly 0 or 1 matches...
+ */
+
+ for (current = first; current <= last; current ++)
+ if (!index_find(ind, element, value, ind->nodes[current]))
+ {
+ /*
+ * Found exactly one (or possibly two) match...
+ */
+
+#ifdef DEBUG
+ printf(" returning only match %d...\n", current);
+#endif /* DEBUG */
+
+ ind->cur_node = current + 1;
+
+ return (ind->nodes[current]);
+ }
+
+ /*
+ * No matches...
+ */
+
+ ind->cur_node = ind->num_nodes;
+
+#ifdef DEBUG
+ puts(" returning NULL...");
+#endif /* DEBUG */
+
+ return (NULL);
+ }
+ else if (ind->cur_node < ind->num_nodes &&
+ !index_find(ind, element, value, ind->nodes[ind->cur_node]))
+ {
+ /*
+ * Return the next matching node...
+ */
+
+#ifdef DEBUG
+ printf(" returning next match %d...\n", ind->cur_node);
+#endif /* DEBUG */
+
+ return (ind->nodes[ind->cur_node ++]);
+ }
+
+ /*
+ * If we get this far, then we have no matches...
+ */
+
+ ind->cur_node = ind->num_nodes;
+
+#ifdef DEBUG
+ puts(" returning NULL...");
+#endif /* DEBUG */
+
+ return (NULL);
+}
+
+
+/*
+ * 'mxmlIndexGetCount()' - Get the number of nodes in an index.
+ *
+ * @since Mini-XML 2.7@
+ */
+
+int /* I - Number of nodes in index */
+mxmlIndexGetCount(mxml_index_t *ind) /* I - Index of nodes */
+{
+ /*
+ * Range check input...
+ */
+
+ if (!ind)
+ return (0);
+
+ /*
+ * Return the number of nodes in the index...
+ */
+
+ return (ind->num_nodes);
+}
+
+
+/*
+ * 'mxmlIndexNew()' - Create a new index.
+ *
+ * The index will contain all nodes that contain the named element and/or
+ * attribute. If both "element" and "attr" are NULL, then the index will
+ * contain a sorted list of the elements in the node tree. Nodes are
+ * sorted by element name and optionally by attribute value if the "attr"
+ * argument is not NULL.
+ */
+
+mxml_index_t * /* O - New index */
+mxmlIndexNew(mxml_node_t *node, /* I - XML node tree */
+ const char *element, /* I - Element to index or NULL for all */
+ const char *attr) /* I - Attribute to index or NULL for none */
+{
+ mxml_index_t *ind; /* New index */
+ mxml_node_t *current, /* Current node in index */
+ **temp; /* Temporary node pointer array */
+
+
+ /*
+ * Range check input...
+ */
+
+#ifdef DEBUG
+ printf("mxmlIndexNew(node=%p, element=\"%s\", attr=\"%s\")\n",
+ node, element ? element : "(null)", attr ? attr : "(null)");
+#endif /* DEBUG */
+
+ if (!node)
+ return (NULL);
+
+ /*
+ * Create a new index...
+ */
+
+ if ((ind = calloc(1, sizeof(mxml_index_t))) == NULL)
+ {
+ mxml_error("Unable to allocate %d bytes for index - %s",
+ sizeof(mxml_index_t), strerror(errno));
+ return (NULL);
+ }
+
+ if (attr)
+ ind->attr = strdup(attr);
+
+ if (!element && !attr)
+ current = node;
+ else
+ current = mxmlFindElement(node, node, element, attr, NULL, MXML_DESCEND);
+
+ while (current)
+ {
+ if (ind->num_nodes >= ind->alloc_nodes)
+ {
+ if (!ind->alloc_nodes)
+ temp = malloc(64 * sizeof(mxml_node_t *));
+ else
+ temp = realloc(ind->nodes, (ind->alloc_nodes + 64) * sizeof(mxml_node_t *));
+
+ if (!temp)
+ {
+ /*
+ * Unable to allocate memory for the index, so abort...
+ */
+
+ mxml_error("Unable to allocate %d bytes for index: %s",
+ (ind->alloc_nodes + 64) * sizeof(mxml_node_t *),
+ strerror(errno));
+
+ mxmlIndexDelete(ind);
+ return (NULL);
+ }
+
+ ind->nodes = temp;
+ ind->alloc_nodes += 64;
+ }
+
+ ind->nodes[ind->num_nodes ++] = current;
+
+ current = mxmlFindElement(current, node, element, attr, NULL, MXML_DESCEND);
+ }
+
+ /*
+ * Sort nodes based upon the search criteria...
+ */
+
+#ifdef DEBUG
+ {
+ int i; /* Looping var */
+
+
+ printf("%d node(s) in index.\n\n", ind->num_nodes);
+
+ if (attr)
+ {
+ printf("Node Address Element %s\n", attr);
+ puts("-------- -------- -------------- ------------------------------");
+
+ for (i = 0; i < ind->num_nodes; i ++)
+ printf("%8d %-8p %-14.14s %s\n", i, ind->nodes[i],
+ ind->nodes[i]->value.element.name,
+ mxmlElementGetAttr(ind->nodes[i], attr));
+ }
+ else
+ {
+ puts("Node Address Element");
+ puts("-------- -------- --------------");
+
+ for (i = 0; i < ind->num_nodes; i ++)
+ printf("%8d %-8p %s\n", i, ind->nodes[i],
+ ind->nodes[i]->value.element.name);
+ }
+
+ putchar('\n');
+ }
+#endif /* DEBUG */
+
+ if (ind->num_nodes > 1)
+ index_sort(ind, 0, ind->num_nodes - 1);
+
+#ifdef DEBUG
+ {
+ int i; /* Looping var */
+
+
+ puts("After sorting:\n");
+
+ if (attr)
+ {
+ printf("Node Address Element %s\n", attr);
+ puts("-------- -------- -------------- ------------------------------");
+
+ for (i = 0; i < ind->num_nodes; i ++)
+ printf("%8d %-8p %-14.14s %s\n", i, ind->nodes[i],
+ ind->nodes[i]->value.element.name,
+ mxmlElementGetAttr(ind->nodes[i], attr));
+ }
+ else
+ {
+ puts("Node Address Element");
+ puts("-------- -------- --------------");
+
+ for (i = 0; i < ind->num_nodes; i ++)
+ printf("%8d %-8p %s\n", i, ind->nodes[i],
+ ind->nodes[i]->value.element.name);
+ }
+
+ putchar('\n');
+ }
+#endif /* DEBUG */
+
+ /*
+ * Return the new index...
+ */
+
+ return (ind);
+}
+
+
+/*
+ * 'mxmlIndexReset()' - Reset the enumeration/find pointer in the index and
+ * return the first node in the index.
+ *
+ * This function should be called prior to using mxmlIndexEnum() or
+ * mxmlIndexFind() for the first time.
+ */
+
+mxml_node_t * /* O - First node or NULL if there is none */
+mxmlIndexReset(mxml_index_t *ind) /* I - Index to reset */
+{
+#ifdef DEBUG
+ printf("mxmlIndexReset(ind=%p)\n", ind);
+#endif /* DEBUG */
+
+ /*
+ * Range check input...
+ */
+
+ if (!ind)
+ return (NULL);
+
+ /*
+ * Set the index to the first element...
+ */
+
+ ind->cur_node = 0;
+
+ /*
+ * Return the first node...
+ */
+
+ if (ind->num_nodes)
+ return (ind->nodes[0]);
+ else
+ return (NULL);
+}
+
+
+/*
+ * 'index_compare()' - Compare two nodes.
+ */
+
+static int /* O - Result of comparison */
+index_compare(mxml_index_t *ind, /* I - Index */
+ mxml_node_t *first, /* I - First node */
+ mxml_node_t *second) /* I - Second node */
+{
+ int diff; /* Difference */
+
+
+ /*
+ * Check the element name...
+ */
+
+ if ((diff = strcmp(first->value.element.name,
+ second->value.element.name)) != 0)
+ return (diff);
+
+ /*
+ * Check the attribute value...
+ */
+
+ if (ind->attr)
+ {
+ if ((diff = strcmp(mxmlElementGetAttr(first, ind->attr),
+ mxmlElementGetAttr(second, ind->attr))) != 0)
+ return (diff);
+ }
+
+ /*
+ * No difference, return 0...
+ */
+
+ return (0);
+}
+
+
+/*
+ * 'index_find()' - Compare a node with index values.
+ */
+
+static int /* O - Result of comparison */
+index_find(mxml_index_t *ind, /* I - Index */
+ const char *element, /* I - Element name or NULL */
+ const char *value, /* I - Attribute value or NULL */
+ mxml_node_t *node) /* I - Node */
+{
+ int diff; /* Difference */
+
+
+ /*
+ * Check the element name...
+ */
+
+ if (element)
+ {
+ if ((diff = strcmp(element, node->value.element.name)) != 0)
+ return (diff);
+ }
+
+ /*
+ * Check the attribute value...
+ */
+
+ if (value)
+ {
+ if ((diff = strcmp(value, mxmlElementGetAttr(node, ind->attr))) != 0)
+ return (diff);
+ }
+
+ /*
+ * No difference, return 0...
+ */
+
+ return (0);
+}
+
+
+/*
+ * 'index_sort()' - Sort the nodes in the index...
+ *
+ * This function implements the classic quicksort algorithm...
+ */
+
+static void
+index_sort(mxml_index_t *ind, /* I - Index to sort */
+ int left, /* I - Left node in partition */
+ int right) /* I - Right node in partition */
+{
+ mxml_node_t *pivot, /* Pivot node */
+ *temp; /* Swap node */
+ int templ, /* Temporary left node */
+ tempr; /* Temporary right node */
+
+
+ /*
+ * Loop until we have sorted all the way to the right...
+ */
+
+ do
+ {
+ /*
+ * Sort the pivot in the current partition...
+ */
+
+ pivot = ind->nodes[left];
+
+ for (templ = left, tempr = right; templ < tempr;)
+ {
+ /*
+ * Move left while left node <= pivot node...
+ */
+
+ while ((templ < right) &&
+ index_compare(ind, ind->nodes[templ], pivot) <= 0)
+ templ ++;
+
+ /*
+ * Move right while right node > pivot node...
+ */
+
+ while ((tempr > left) &&
+ index_compare(ind, ind->nodes[tempr], pivot) > 0)
+ tempr --;
+
+ /*
+ * Swap nodes if needed...
+ */
+
+ if (templ < tempr)
+ {
+ temp = ind->nodes[templ];
+ ind->nodes[templ] = ind->nodes[tempr];
+ ind->nodes[tempr] = temp;
+ }
+ }
+
+ /*
+ * When we get here, the right (tempr) node is the new position for the
+ * pivot node...
+ */
+
+ if (index_compare(ind, pivot, ind->nodes[tempr]) > 0)
+ {
+ ind->nodes[left] = ind->nodes[tempr];
+ ind->nodes[tempr] = pivot;
+ }
+
+ /*
+ * Recursively sort the left partition as needed...
+ */
+
+ if (left < (tempr - 1))
+ index_sort(ind, left, tempr - 1);
+ }
+ while (right > (left = tempr + 1));
+}
+
+
+/*
+ * End of "$Id: mxml-index.c 451 2014-01-04 21:50:06Z msweet $".
+ */
diff --git a/emb/pastilda/lib/miniXML/mxml-node.c b/emb/pastilda/lib/miniXML/mxml-node.c
new file mode 100644
index 0000000..40426d0
--- /dev/null
+++ b/emb/pastilda/lib/miniXML/mxml-node.c
@@ -0,0 +1,842 @@
+/*
+ * "$Id: mxml-node.c 462 2016-06-11 20:51:49Z msweet $"
+ *
+ * Node support code for Mini-XML, a small XML-like file parsing library.
+ *
+ * Copyright 2003-2016 by Michael R Sweet.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Michael R Sweet and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "COPYING"
+ * which should have been included with this file. If this file is
+ * missing or damaged, see the license at:
+ *
+ * http://www.msweet.org/projects.php/Mini-XML
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "config.h"
+#include "mxml.h"
+
+
+/*
+ * Local functions...
+ */
+
+static void mxml_free(mxml_node_t *node);
+static mxml_node_t *mxml_new(mxml_node_t *parent, mxml_type_t type);
+
+
+/*
+ * 'mxmlAdd()' - Add a node to a tree.
+ *
+ * Adds the specified node to the parent. If the child argument is not
+ * NULL, puts the new node before or after the specified child depending
+ * on the value of the where argument. If the child argument is NULL,
+ * puts the new node at the beginning of the child list (MXML_ADD_BEFORE)
+ * or at the end of the child list (MXML_ADD_AFTER). The constant
+ * MXML_ADD_TO_PARENT can be used to specify a NULL child pointer.
+ */
+
+void
+mxmlAdd(mxml_node_t *parent, /* I - Parent node */
+ int where, /* I - Where to add, MXML_ADD_BEFORE or MXML_ADD_AFTER */
+ mxml_node_t *child, /* I - Child node for where or MXML_ADD_TO_PARENT */
+ mxml_node_t *node) /* I - Node to add */
+{
+#ifdef DEBUG
+ fprintf(stderr, "mxmlAdd(parent=%p, where=%d, child=%p, node=%p)\n", parent,
+ where, child, node);
+#endif /* DEBUG */
+
+ /*
+ * Range check input...
+ */
+
+ if (!parent || !node)
+ return;
+
+#if DEBUG > 1
+ fprintf(stderr, " BEFORE: node->parent=%p\n", node->parent);
+ if (parent)
+ {
+ fprintf(stderr, " BEFORE: parent->child=%p\n", parent->child);
+ fprintf(stderr, " BEFORE: parent->last_child=%p\n", parent->last_child);
+ fprintf(stderr, " BEFORE: parent->prev=%p\n", parent->prev);
+ fprintf(stderr, " BEFORE: parent->next=%p\n", parent->next);
+ }
+#endif /* DEBUG > 1 */
+
+ /*
+ * Remove the node from any existing parent...
+ */
+
+ if (node->parent)
+ mxmlRemove(node);
+
+ /*
+ * Reset pointers...
+ */
+
+ node->parent = parent;
+
+ switch (where)
+ {
+ case MXML_ADD_BEFORE :
+ if (!child || child == parent->child || child->parent != parent)
+ {
+ /*
+ * Insert as first node under parent...
+ */
+
+ node->next = parent->child;
+
+ if (parent->child)
+ parent->child->prev = node;
+ else
+ parent->last_child = node;
+
+ parent->child = node;
+ }
+ else
+ {
+ /*
+ * Insert node before this child...
+ */
+
+ node->next = child;
+ node->prev = child->prev;
+
+ if (child->prev)
+ child->prev->next = node;
+ else
+ parent->child = node;
+
+ child->prev = node;
+ }
+ break;
+
+ case MXML_ADD_AFTER :
+ if (!child || child == parent->last_child || child->parent != parent)
+ {
+ /*
+ * Insert as last node under parent...
+ */
+
+ node->parent = parent;
+ node->prev = parent->last_child;
+
+ if (parent->last_child)
+ parent->last_child->next = node;
+ else
+ parent->child = node;
+
+ parent->last_child = node;
+ }
+ else
+ {
+ /*
+ * Insert node after this child...
+ */
+
+ node->prev = child;
+ node->next = child->next;
+
+ if (child->next)
+ child->next->prev = node;
+ else
+ parent->last_child = node;
+
+ child->next = node;
+ }
+ break;
+ }
+
+#if DEBUG > 1
+ fprintf(stderr, " AFTER: node->parent=%p\n", node->parent);
+ if (parent)
+ {
+ fprintf(stderr, " AFTER: parent->child=%p\n", parent->child);
+ fprintf(stderr, " AFTER: parent->last_child=%p\n", parent->last_child);
+ fprintf(stderr, " AFTER: parent->prev=%p\n", parent->prev);
+ fprintf(stderr, " AFTER: parent->next=%p\n", parent->next);
+ }
+#endif /* DEBUG > 1 */
+}
+
+
+/*
+ * 'mxmlDelete()' - Delete a node and all of its children.
+ *
+ * If the specified node has a parent, this function first removes the
+ * node from its parent using the mxmlRemove() function.
+ */
+
+void
+mxmlDelete(mxml_node_t *node) /* I - Node to delete */
+{
+ mxml_node_t *current, /* Current node */
+ *next; /* Next node */
+
+
+#ifdef DEBUG
+ fprintf(stderr, "mxmlDelete(node=%p)\n", node);
+#endif /* DEBUG */
+
+ /*
+ * Range check input...
+ */
+
+ if (!node)
+ return;
+
+ /*
+ * Remove the node from its parent, if any...
+ */
+
+ mxmlRemove(node);
+
+ /*
+ * Delete children...
+ */
+
+ for (current = node->child; current; current = next)
+ {
+ /*
+ * Get the next node...
+ */
+
+ if ((next = current->child) != NULL)
+ {
+ /*
+ * Free parent nodes after child nodes have been freed...
+ */
+
+ current->child = NULL;
+ continue;
+ }
+
+ if ((next = current->next) == NULL)
+ {
+ mxml_node_t *temp = current->parent;
+ /* Pointer to parent node */
+
+ if (temp == node)
+ {
+ /*
+ * Got back to the top node...
+ */
+
+ next = NULL;
+ }
+ else if ((next = temp->next) == NULL)
+ {
+ if ((next = temp->parent) == node)
+ next = NULL;
+ }
+ }
+
+ mxml_free(current);
+ }
+
+ /*
+ * Then free the memory used by this node...
+ */
+
+ mxml_free(node);
+}
+
+
+/*
+ * 'mxmlGetRefCount()' - Get the current reference (use) count for a node.
+ *
+ * The initial reference count of new nodes is 1. Use the @link mxmlRetain@
+ * and @link mxmlRelease@ functions to increment and decrement a node's
+ * reference count.
+ *
+ * @since Mini-XML 2.7@.
+ */
+
+int /* O - Reference count */
+mxmlGetRefCount(mxml_node_t *node) /* I - Node */
+{
+ /*
+ * Range check input...
+ */
+
+ if (!node)
+ return (0);
+
+ /*
+ * Return the reference count...
+ */
+
+ return (node->ref_count);
+}
+
+
+/*
+ * 'mxmlNewCDATA()' - Create a new CDATA node.
+ *
+ * The new CDATA node is added to the end of the specified parent's child
+ * list. The constant MXML_NO_PARENT can be used to specify that the new
+ * CDATA node has no parent. The data string must be nul-terminated and
+ * is copied into the new node. CDATA nodes use the MXML_ELEMENT type.
+ *
+ * @since Mini-XML 2.3@
+ */
+
+mxml_node_t * /* O - New node */
+mxmlNewCDATA(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */
+ const char *data) /* I - Data string */
+{
+ mxml_node_t *node; /* New node */
+
+
+#ifdef DEBUG
+ fprintf(stderr, "mxmlNewCDATA(parent=%p, data=\"%s\")\n",
+ parent, data ? data : "(null)");
+#endif /* DEBUG */
+
+ /*
+ * Range check input...
+ */
+
+ if (!data)
+ return (NULL);
+
+ /*
+ * Create the node and set the name value...
+ */
+
+ if ((node = mxml_new(parent, MXML_ELEMENT)) != NULL)
+ node->value.element.name = _mxml_strdupf("![CDATA[%s]]", data);
+
+ return (node);
+}
+
+
+/*
+ * 'mxmlNewCustom()' - Create a new custom data node.
+ *
+ * The new custom node is added to the end of the specified parent's child
+ * list. The constant MXML_NO_PARENT can be used to specify that the new
+ * element node has no parent. NULL can be passed when the data in the
+ * node is not dynamically allocated or is separately managed.
+ *
+ * @since Mini-XML 2.1@
+ */
+
+mxml_node_t * /* O - New node */
+mxmlNewCustom(
+ mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */
+ void *data, /* I - Pointer to data */
+ mxml_custom_destroy_cb_t destroy) /* I - Function to destroy data */
+{
+ mxml_node_t *node; /* New node */
+
+
+#ifdef DEBUG
+ fprintf(stderr, "mxmlNewCustom(parent=%p, data=%p, destroy=%p)\n", parent,
+ data, destroy);
+#endif /* DEBUG */
+
+ /*
+ * Create the node and set the value...
+ */
+
+ if ((node = mxml_new(parent, MXML_CUSTOM)) != NULL)
+ {
+ node->value.custom.data = data;
+ node->value.custom.destroy = destroy;
+ }
+
+ return (node);
+}
+
+
+/*
+ * 'mxmlNewElement()' - Create a new element node.
+ *
+ * The new element node is added to the end of the specified parent's child
+ * list. The constant MXML_NO_PARENT can be used to specify that the new
+ * element node has no parent.
+ */
+
+mxml_node_t * /* O - New node */
+mxmlNewElement(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */
+ const char *name) /* I - Name of element */
+{
+ mxml_node_t *node; /* New node */
+
+
+#ifdef DEBUG
+ fprintf(stderr, "mxmlNewElement(parent=%p, name=\"%s\")\n", parent,
+ name ? name : "(null)");
+#endif /* DEBUG */
+
+ /*
+ * Range check input...
+ */
+
+ if (!name)
+ return (NULL);
+
+ /*
+ * Create the node and set the element name...
+ */
+
+ if ((node = mxml_new(parent, MXML_ELEMENT)) != NULL)
+ node->value.element.name = strdup(name);
+
+ return (node);
+}
+
+
+/*
+ * 'mxmlNewInteger()' - Create a new integer node.
+ *
+ * The new integer node is added to the end of the specified parent's child
+ * list. The constant MXML_NO_PARENT can be used to specify that the new
+ * integer node has no parent.
+ */
+
+mxml_node_t * /* O - New node */
+mxmlNewInteger(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */
+ int integer) /* I - Integer value */
+{
+ mxml_node_t *node; /* New node */
+
+
+#ifdef DEBUG
+ fprintf(stderr, "mxmlNewInteger(parent=%p, integer=%d)\n", parent, integer);
+#endif /* DEBUG */
+
+ /*
+ * Create the node and set the element name...
+ */
+
+ if ((node = mxml_new(parent, MXML_INTEGER)) != NULL)
+ node->value.integer = integer;
+
+ return (node);
+}
+
+
+/*
+ * 'mxmlNewOpaque()' - Create a new opaque string.
+ *
+ * The new opaque node is added to the end of the specified parent's child
+ * list. The constant MXML_NO_PARENT can be used to specify that the new
+ * opaque node has no parent. The opaque string must be nul-terminated and
+ * is copied into the new node.
+ */
+
+mxml_node_t * /* O - New node */
+mxmlNewOpaque(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */
+ const char *opaque) /* I - Opaque string */
+{
+ mxml_node_t *node; /* New node */
+
+
+#ifdef DEBUG
+ fprintf(stderr, "mxmlNewOpaque(parent=%p, opaque=\"%s\")\n", parent,
+ opaque ? opaque : "(null)");
+#endif /* DEBUG */
+
+ /*
+ * Range check input...
+ */
+
+ if (!opaque)
+ return (NULL);
+
+ /*
+ * Create the node and set the element name...
+ */
+
+ if ((node = mxml_new(parent, MXML_OPAQUE)) != NULL)
+ node->value.opaque = strdup(opaque);
+
+ return (node);
+}
+
+
+/*
+ * 'mxmlNewReal()' - Create a new real number node.
+ *
+ * The new real number node is added to the end of the specified parent's
+ * child list. The constant MXML_NO_PARENT can be used to specify that
+ * the new real number node has no parent.
+ */
+
+mxml_node_t * /* O - New node */
+mxmlNewReal(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */
+ double real) /* I - Real number value */
+{
+ mxml_node_t *node; /* New node */
+
+
+#ifdef DEBUG
+ fprintf(stderr, "mxmlNewReal(parent=%p, real=%g)\n", parent, real);
+#endif /* DEBUG */
+
+ /*
+ * Create the node and set the element name...
+ */
+
+ if ((node = mxml_new(parent, MXML_REAL)) != NULL)
+ node->value.real = real;
+
+ return (node);
+}
+
+
+/*
+ * 'mxmlNewText()' - Create a new text fragment node.
+ *
+ * The new text node is added to the end of the specified parent's child
+ * list. The constant MXML_NO_PARENT can be used to specify that the new
+ * text node has no parent. The whitespace parameter is used to specify
+ * whether leading whitespace is present before the node. The text
+ * string must be nul-terminated and is copied into the new node.
+ */
+
+mxml_node_t * /* O - New node */
+mxmlNewText(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */
+ int whitespace, /* I - 1 = leading whitespace, 0 = no whitespace */
+ const char *string) /* I - String */
+{
+ mxml_node_t *node; /* New node */
+
+
+#ifdef DEBUG
+ fprintf(stderr, "mxmlNewText(parent=%p, whitespace=%d, string=\"%s\")\n",
+ parent, whitespace, string ? string : "(null)");
+#endif /* DEBUG */
+
+ /*
+ * Range check input...
+ */
+
+ if (!string)
+ return (NULL);
+
+ /*
+ * Create the node and set the text value...
+ */
+
+ if ((node = mxml_new(parent, MXML_TEXT)) != NULL)
+ {
+ node->value.text.whitespace = whitespace;
+ node->value.text.string = strdup(string);
+ }
+
+ return (node);
+}
+
+
+/*
+ * 'mxmlNewTextf()' - Create a new formatted text fragment node.
+ *
+ * The new text node is added to the end of the specified parent's child
+ * list. The constant MXML_NO_PARENT can be used to specify that the new
+ * text node has no parent. The whitespace parameter is used to specify
+ * whether leading whitespace is present before the node. The format
+ * string must be nul-terminated and is formatted into the new node.
+ */
+
+mxml_node_t * /* O - New node */
+mxmlNewTextf(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */
+ int whitespace, /* I - 1 = leading whitespace, 0 = no whitespace */
+ const char *format, /* I - Printf-style frmat string */
+ ...) /* I - Additional args as needed */
+{
+ mxml_node_t *node; /* New node */
+ va_list ap; /* Pointer to arguments */
+
+
+#ifdef DEBUG
+ fprintf(stderr, "mxmlNewTextf(parent=%p, whitespace=%d, format=\"%s\", ...)\n",
+ parent, whitespace, format ? format : "(null)");
+#endif /* DEBUG */
+
+ /*
+ * Range check input...
+ */
+
+ if (!format)
+ return (NULL);
+
+ /*
+ * Create the node and set the text value...
+ */
+
+ if ((node = mxml_new(parent, MXML_TEXT)) != NULL)
+ {
+ va_start(ap, format);
+
+ node->value.text.whitespace = whitespace;
+ node->value.text.string = _mxml_vstrdupf(format, ap);
+
+ va_end(ap);
+ }
+
+ return (node);
+}
+
+
+/*
+ * 'mxmlRemove()' - Remove a node from its parent.
+ *
+ * Does not free memory used by the node - use mxmlDelete() for that.
+ * This function does nothing if the node has no parent.
+ */
+
+void
+mxmlRemove(mxml_node_t *node) /* I - Node to remove */
+{
+#ifdef DEBUG
+ fprintf(stderr, "mxmlRemove(node=%p)\n", node);
+#endif /* DEBUG */
+
+ /*
+ * Range check input...
+ */
+
+ if (!node || !node->parent)
+ return;
+
+ /*
+ * Remove from parent...
+ */
+
+#if DEBUG > 1
+ fprintf(stderr, " BEFORE: node->parent=%p\n", node->parent);
+ if (node->parent)
+ {
+ fprintf(stderr, " BEFORE: node->parent->child=%p\n", node->parent->child);
+ fprintf(stderr, " BEFORE: node->parent->last_child=%p\n", node->parent->last_child);
+ }
+ fprintf(stderr, " BEFORE: node->child=%p\n", node->child);
+ fprintf(stderr, " BEFORE: node->last_child=%p\n", node->last_child);
+ fprintf(stderr, " BEFORE: node->prev=%p\n", node->prev);
+ fprintf(stderr, " BEFORE: node->next=%p\n", node->next);
+#endif /* DEBUG > 1 */
+
+ if (node->prev)
+ node->prev->next = node->next;
+ else
+ node->parent->child = node->next;
+
+ if (node->next)
+ node->next->prev = node->prev;
+ else
+ node->parent->last_child = node->prev;
+
+ node->parent = NULL;
+ node->prev = NULL;
+ node->next = NULL;
+
+#if DEBUG > 1
+ fprintf(stderr, " AFTER: node->parent=%p\n", node->parent);
+ if (node->parent)
+ {
+ fprintf(stderr, " AFTER: node->parent->child=%p\n", node->parent->child);
+ fprintf(stderr, " AFTER: node->parent->last_child=%p\n", node->parent->last_child);
+ }
+ fprintf(stderr, " AFTER: node->child=%p\n", node->child);
+ fprintf(stderr, " AFTER: node->last_child=%p\n", node->last_child);
+ fprintf(stderr, " AFTER: node->prev=%p\n", node->prev);
+ fprintf(stderr, " AFTER: node->next=%p\n", node->next);
+#endif /* DEBUG > 1 */
+}
+
+
+/*
+ * 'mxmlNewXML()' - Create a new XML document tree.
+ *
+ * The "version" argument specifies the version number to put in the
+ * ?xml element node. If NULL, version 1.0 is assumed.
+ *
+ * @since Mini-XML 2.3@
+ */
+
+mxml_node_t * /* O - New ?xml node */
+mxmlNewXML(const char *version) /* I - Version number to use */
+{
+ char element[1024]; /* Element text */
+
+
+ snprintf(element, sizeof(element), "?xml version=\"%s\" encoding=\"utf-8\"?",
+ version ? version : "1.0");
+
+ return (mxmlNewElement(NULL, element));
+}
+
+
+/*
+ * 'mxmlRelease()' - Release a node.
+ *
+ * When the reference count reaches zero, the node (and any children)
+ * is deleted via mxmlDelete().
+ *
+ * @since Mini-XML 2.3@
+ */
+
+int /* O - New reference count */
+mxmlRelease(mxml_node_t *node) /* I - Node */
+{
+ if (node)
+ {
+ if ((-- node->ref_count) <= 0)
+ {
+ mxmlDelete(node);
+ return (0);
+ }
+ else
+ return (node->ref_count);
+ }
+ else
+ return (-1);
+}
+
+
+/*
+ * 'mxmlRetain()' - Retain a node.
+ *
+ * @since Mini-XML 2.3@
+ */
+
+int /* O - New reference count */
+mxmlRetain(mxml_node_t *node) /* I - Node */
+{
+ if (node)
+ return (++ node->ref_count);
+ else
+ return (-1);
+}
+
+
+/*
+ * 'mxml_free()' - Free the memory used by a node.
+ *
+ * Note: Does not free child nodes, does not remove from parent.
+ */
+
+static void
+mxml_free(mxml_node_t *node) /* I - Node */
+{
+ int i; /* Looping var */
+
+
+ switch (node->type)
+ {
+ case MXML_ELEMENT :
+ if (node->value.element.name)
+ free(node->value.element.name);
+
+ if (node->value.element.num_attrs)
+ {
+ for (i = 0; i < node->value.element.num_attrs; i ++)
+ {
+ if (node->value.element.attrs[i].name)
+ free(node->value.element.attrs[i].name);
+ if (node->value.element.attrs[i].value)
+ free(node->value.element.attrs[i].value);
+ }
+
+ free(node->value.element.attrs);
+ }
+ break;
+ case MXML_INTEGER :
+ /* Nothing to do */
+ break;
+ case MXML_OPAQUE :
+ if (node->value.opaque)
+ free(node->value.opaque);
+ break;
+ case MXML_REAL :
+ /* Nothing to do */
+ break;
+ case MXML_TEXT :
+ if (node->value.text.string)
+ free(node->value.text.string);
+ break;
+ case MXML_CUSTOM :
+ if (node->value.custom.data &&
+ node->value.custom.destroy)
+ (*(node->value.custom.destroy))(node->value.custom.data);
+ break;
+ default :
+ break;
+ }
+
+ /*
+ * Free this node...
+ */
+
+ free(node);
+}
+
+
+/*
+ * 'mxml_new()' - Create a new node.
+ */
+
+static mxml_node_t * /* O - New node */
+mxml_new(mxml_node_t *parent, /* I - Parent node */
+ mxml_type_t type) /* I - Node type */
+{
+ mxml_node_t *node; /* New node */
+
+
+#if DEBUG > 1
+ fprintf(stderr, "mxml_new(parent=%p, type=%d)\n", parent, type);
+#endif /* DEBUG > 1 */
+
+ /*
+ * Allocate memory for the node...
+ */
+
+ if ((node = calloc(1, sizeof(mxml_node_t))) == NULL)
+ {
+#if DEBUG > 1
+ fputs(" returning NULL\n", stderr);
+#endif /* DEBUG > 1 */
+
+ return (NULL);
+ }
+
+#if DEBUG > 1
+ fprintf(stderr, " returning %p\n", node);
+#endif /* DEBUG > 1 */
+
+ /*
+ * Set the node type...
+ */
+
+ node->type = type;
+ node->ref_count = 1;
+
+ /*
+ * Add to the parent if present...
+ */
+
+ if (parent)
+ mxmlAdd(parent, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, node);
+
+ /*
+ * Return the new node...
+ */
+
+ return (node);
+}
+
+
+/*
+ * End of "$Id: mxml-node.c 462 2016-06-11 20:51:49Z msweet $".
+ */
diff --git a/emb/pastilda/lib/miniXML/mxml-private.c b/emb/pastilda/lib/miniXML/mxml-private.c
new file mode 100644
index 0000000..bec4bbf
--- /dev/null
+++ b/emb/pastilda/lib/miniXML/mxml-private.c
@@ -0,0 +1,323 @@
+/*
+ * "$Id: mxml-private.c 451 2014-01-04 21:50:06Z msweet $"
+ *
+ * Private functions for Mini-XML, a small XML-like file parsing library.
+ *
+ * Copyright 2003-2014 by Michael R Sweet.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Michael R Sweet and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "COPYING"
+ * which should have been included with this file. If this file is
+ * missing or damaged, see the license at:
+ *
+ * http://www.msweet.org/projects.php/Mini-XML
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "mxml-private.h"
+
+
+/*
+ * Some crazy people think that unloading a shared object is a good or safe
+ * thing to do. Unfortunately, most objects are simply *not* safe to unload
+ * and bad things *will* happen.
+ *
+ * The following mess of conditional code allows us to provide a destructor
+ * function in Mini-XML for our thread-global storage so that it can possibly
+ * be unloaded safely, although since there is no standard way to do so I
+ * can't even provide any guarantees that you can do it safely on all platforms.
+ *
+ * This code currently supports AIX, HP-UX, Linux, Mac OS X, Solaris, and
+ * Windows. It might work on the BSDs and IRIX, but I haven't tested that.
+ */
+
+#if defined(__sun) || defined(_AIX)
+# pragma fini(_mxml_fini)
+# define _MXML_FINI _mxml_fini
+#elif defined(__hpux)
+# pragma FINI _mxml_fini
+# define _MXML_FINI _mxml_fini
+#elif defined(__GNUC__) /* Linux and Mac OS X */
+# define _MXML_FINI __attribute((destructor)) _mxml_fini
+#else
+# define _MXML_FINI _fini
+#endif /* __sun */
+
+
+/*
+ * 'mxml_error()' - Display an error message.
+ */
+
+void
+mxml_error(const char *format, /* I - Printf-style format string */
+ ...) /* I - Additional arguments as needed */
+{
+ va_list ap; /* Pointer to arguments */
+ char s[1024]; /* Message string */
+ _mxml_global_t *global = _mxml_global();
+ /* Global data */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!format)
+ return;
+
+ /*
+ * Format the error message string...
+ */
+
+ va_start(ap, format);
+
+ vsnprintf(s, sizeof(s), format, ap);
+
+ va_end(ap);
+
+ /*
+ * And then display the error message...
+ */
+
+ if (global->error_cb)
+ (*global->error_cb)(s);
+ else
+ fprintf(stderr, "mxml: %s\n", s);
+}
+
+
+/*
+ * 'mxml_ignore_cb()' - Default callback for ignored values.
+ */
+
+mxml_type_t /* O - Node type */
+mxml_ignore_cb(mxml_node_t *node) /* I - Current node */
+{
+ (void)node;
+
+ return (MXML_IGNORE);
+}
+
+
+/*
+ * 'mxml_integer_cb()' - Default callback for integer values.
+ */
+
+mxml_type_t /* O - Node type */
+mxml_integer_cb(mxml_node_t *node) /* I - Current node */
+{
+ (void)node;
+
+ return (MXML_INTEGER);
+}
+
+
+/*
+ * 'mxml_opaque_cb()' - Default callback for opaque values.
+ */
+
+mxml_type_t /* O - Node type */
+mxml_opaque_cb(mxml_node_t *node) /* I - Current node */
+{
+ (void)node;
+
+ return (MXML_OPAQUE);
+}
+
+
+/*
+ * 'mxml_real_cb()' - Default callback for real number values.
+ */
+
+mxml_type_t /* O - Node type */
+mxml_real_cb(mxml_node_t *node) /* I - Current node */
+{
+ (void)node;
+
+ return (MXML_REAL);
+}
+
+
+#ifdef HAVE_PTHREAD_H /**** POSIX threading ****/
+# include <pthread.h>
+
+static pthread_key_t _mxml_key = -1; /* Thread local storage key */
+static pthread_once_t _mxml_key_once = PTHREAD_ONCE_INIT;
+ /* One-time initialization object */
+static void _mxml_init(void);
+static void _mxml_destructor(void *g);
+
+
+/*
+ * '_mxml_destructor()' - Free memory used for globals...
+ */
+
+static void
+_mxml_destructor(void *g) /* I - Global data */
+{
+ free(g);
+}
+
+
+/*
+ * '_mxml_fini()' - Clean up when unloaded.
+ */
+
+static void
+_MXML_FINI(void)
+{
+ _mxml_global_t *global; /* Global data */
+
+
+ if (_mxml_key != -1)
+ {
+ if ((global = (_mxml_global_t *)pthread_getspecific(_mxml_key)) != NULL)
+ _mxml_destructor(global);
+
+ pthread_key_delete(_mxml_key);
+ _mxml_key = -1;
+ }
+}
+
+
+/*
+ * '_mxml_global()' - Get global data.
+ */
+
+_mxml_global_t * /* O - Global data */
+_mxml_global(void)
+{
+ _mxml_global_t *global; /* Global data */
+
+
+ pthread_once(&_mxml_key_once, _mxml_init);
+
+ if ((global = (_mxml_global_t *)pthread_getspecific(_mxml_key)) == NULL)
+ {
+ global = (_mxml_global_t *)calloc(1, sizeof(_mxml_global_t));
+ pthread_setspecific(_mxml_key, global);
+
+ global->num_entity_cbs = 1;
+ global->entity_cbs[0] = _mxml_entity_cb;
+ global->wrap = 72;
+ }
+
+ return (global);
+}
+
+
+/*
+ * '_mxml_init()' - Initialize global data...
+ */
+
+static void
+_mxml_init(void)
+{
+ pthread_key_create(&_mxml_key, _mxml_destructor);
+}
+
+
+#elif defined(WIN32) && defined(MXML1_EXPORTS) /**** WIN32 threading ****/
+# include <windows.h>
+
+static DWORD _mxml_tls_index; /* Index for global storage */
+
+
+/*
+ * 'DllMain()' - Main entry for library.
+ */
+
+BOOL WINAPI /* O - Success/failure */
+DllMain(HINSTANCE hinst, /* I - DLL module handle */
+ DWORD reason, /* I - Reason */
+ LPVOID reserved) /* I - Unused */
+{
+ _mxml_global_t *global; /* Global data */
+
+
+ (void)hinst;
+ (void)reserved;
+
+ switch (reason)
+ {
+ case DLL_PROCESS_ATTACH : /* Called on library initialization */
+ if ((_mxml_tls_index = TlsAlloc()) == TLS_OUT_OF_INDEXES)
+ return (FALSE);
+ break;
+
+ case DLL_THREAD_DETACH : /* Called when a thread terminates */
+ if ((global = (_mxml_global_t *)TlsGetValue(_mxml_tls_index)) != NULL)
+ free(global);
+ break;
+
+ case DLL_PROCESS_DETACH : /* Called when library is unloaded */
+ if ((global = (_mxml_global_t *)TlsGetValue(_mxml_tls_index)) != NULL)
+ free(global);
+
+ TlsFree(_mxml_tls_index);
+ break;
+
+ default:
+ break;
+ }
+
+ return (TRUE);
+}
+
+
+/*
+ * '_mxml_global()' - Get global data.
+ */
+
+_mxml_global_t * /* O - Global data */
+_mxml_global(void)
+{
+ _mxml_global_t *global; /* Global data */
+
+
+ if ((global = (_mxml_global_t *)TlsGetValue(_mxml_tls_index)) == NULL)
+ {
+ global = (_mxml_global_t *)calloc(1, sizeof(_mxml_global_t));
+
+ global->num_entity_cbs = 1;
+ global->entity_cbs[0] = _mxml_entity_cb;
+ global->wrap = 72;
+
+ TlsSetValue(_mxml_tls_index, (LPVOID)global);
+ }
+
+ return (global);
+}
+
+
+#else /**** No threading ****/
+/*
+ * '_mxml_global()' - Get global data.
+ */
+
+_mxml_global_t * /* O - Global data */
+_mxml_global(void)
+{
+ static _mxml_global_t global = /* Global data */
+ {
+ NULL, /* error_cb */
+ 1, /* num_entity_cbs */
+ { _mxml_entity_cb }, /* entity_cbs */
+ 72, /* wrap */
+ NULL, /* custom_load_cb */
+ NULL /* custom_save_cb */
+ };
+
+
+ return (&global);
+}
+#endif /* HAVE_PTHREAD_H */
+
+
+/*
+ * End of "$Id: mxml-private.c 451 2014-01-04 21:50:06Z msweet $".
+ */
diff --git a/emb/pastilda/lib/miniXML/mxml-private.h b/emb/pastilda/lib/miniXML/mxml-private.h
new file mode 100644
index 0000000..c5e4e6b
--- /dev/null
+++ b/emb/pastilda/lib/miniXML/mxml-private.h
@@ -0,0 +1,50 @@
+/*
+ * "$Id: mxml-private.h 451 2014-01-04 21:50:06Z msweet $"
+ *
+ * Private definitions for Mini-XML, a small XML-like file parsing library.
+ *
+ * Copyright 2003-2014 by Michael R Sweet.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Michael R Sweet and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "COPYING"
+ * which should have been included with this file. If this file is
+ * missing or damaged, see the license at:
+ *
+ * http://www.msweet.org/projects.php/Mini-XML
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "config.h"
+#include "mxml.h"
+
+
+/*
+ * Global, per-thread data...
+ */
+
+typedef struct _mxml_global_s
+{
+ void (*error_cb)(const char *);
+ int num_entity_cbs;
+ int (*entity_cbs[100])(const char *name);
+ int wrap;
+ mxml_custom_load_cb_t custom_load_cb;
+ mxml_custom_save_cb_t custom_save_cb;
+} _mxml_global_t;
+
+
+/*
+ * Functions...
+ */
+
+extern _mxml_global_t *_mxml_global(void);
+extern int _mxml_entity_cb(const char *name);
+
+
+/*
+ * End of "$Id: mxml-private.h 451 2014-01-04 21:50:06Z msweet $".
+ */
diff --git a/emb/pastilda/lib/miniXML/mxml-search.c b/emb/pastilda/lib/miniXML/mxml-search.c
new file mode 100644
index 0000000..313a52f
--- /dev/null
+++ b/emb/pastilda/lib/miniXML/mxml-search.c
@@ -0,0 +1,280 @@
+/*
+ * "$Id: mxml-search.c 451 2014-01-04 21:50:06Z msweet $"
+ *
+ * Search/navigation functions for Mini-XML, a small XML-like file
+ * parsing library.
+ *
+ * Copyright 2003-2014 by Michael R Sweet.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Michael R Sweet and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "COPYING"
+ * which should have been included with this file. If this file is
+ * missing or damaged, see the license at:
+ *
+ * http://www.msweet.org/projects.php/Mini-XML
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "config.h"
+#include "mxml.h"
+
+
+/*
+ * 'mxmlFindElement()' - Find the named element.
+ *
+ * The search is constrained by the name, attribute name, and value; any
+ * NULL names or values are treated as wildcards, so different kinds of
+ * searches can be implemented by looking for all elements of a given name
+ * or all elements with a specific attribute. The descend argument determines
+ * whether the search descends into child nodes; normally you will use
+ * MXML_DESCEND_FIRST for the initial search and MXML_NO_DESCEND to find
+ * additional direct descendents of the node. The top node argument
+ * constrains the search to a particular node's children.
+ */
+
+mxml_node_t * /* O - Element node or NULL */
+mxmlFindElement(mxml_node_t *node, /* I - Current node */
+ mxml_node_t *top, /* I - Top node */
+ const char *name, /* I - Element name or NULL for any */
+ const char *attr, /* I - Attribute name, or NULL for none */
+ const char *value, /* I - Attribute value, or NULL for any */
+ int descend) /* I - Descend into tree - MXML_DESCEND, MXML_NO_DESCEND, or MXML_DESCEND_FIRST */
+{
+ const char *temp; /* Current attribute value */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!node || !top || (!attr && value))
+ return (NULL);
+
+ /*
+ * Start with the next node...
+ */
+
+ node = mxmlWalkNext(node, top, descend);
+
+ /*
+ * Loop until we find a matching element...
+ */
+
+ while (node != NULL)
+ {
+ /*
+ * See if this node matches...
+ */
+
+ if (node->type == MXML_ELEMENT &&
+ node->value.element.name &&
+ (!name || !strcmp(node->value.element.name, name)))
+ {
+ /*
+ * See if we need to check for an attribute...
+ */
+
+ if (!attr)
+ return (node); /* No attribute search, return it... */
+
+ /*
+ * Check for the attribute...
+ */
+
+ if ((temp = mxmlElementGetAttr(node, attr)) != NULL)
+ {
+ /*
+ * OK, we have the attribute, does it match?
+ */
+
+ if (!value || !strcmp(value, temp))
+ return (node); /* Yes, return it... */
+ }
+ }
+
+ /*
+ * No match, move on to the next node...
+ */
+
+ if (descend == MXML_DESCEND)
+ node = mxmlWalkNext(node, top, MXML_DESCEND);
+ else
+ node = node->next;
+ }
+
+ return (NULL);
+}
+
+
+/*
+ * 'mxmlFindPath()' - Find a node with the given path.
+ *
+ * The "path" is a slash-separated list of element names. The name "*" is
+ * considered a wildcard for one or more levels of elements. For example,
+ * "foo/one/two", "bar/two/one", "*\/one", and so forth.
+ *
+ * The first child node of the found node is returned if the given node has
+ * children and the first child is a value node.
+ *
+ * @since Mini-XML 2.7@
+ */
+
+mxml_node_t * /* O - Found node or NULL */
+mxmlFindPath(mxml_node_t *top, /* I - Top node */
+ const char *path) /* I - Path to element */
+{
+ mxml_node_t *node; /* Current node */
+ char element[256]; /* Current element name */
+ const char *pathsep; /* Separator in path */
+ int descend; /* mxmlFindElement option */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!top || !path || !*path)
+ return (NULL);
+
+ /*
+ * Search each element in the path...
+ */
+
+ node = top;
+ while (*path)
+ {
+ /*
+ * Handle wildcards...
+ */
+
+ if (!strncmp(path, "*/", 2))
+ {
+ path += 2;
+ descend = MXML_DESCEND;
+ }
+ else
+ descend = MXML_DESCEND_FIRST;
+
+ /*
+ * Get the next element in the path...
+ */
+
+ if ((pathsep = strchr(path, '/')) == NULL)
+ pathsep = path + strlen(path);
+
+ if (pathsep == path || (pathsep - path) >= sizeof(element))
+ return (NULL);
+
+ memcpy(element, path, pathsep - path);
+ element[pathsep - path] = '\0';
+
+ if (*pathsep)
+ path = pathsep + 1;
+ else
+ path = pathsep;
+
+ /*
+ * Search for the element...
+ */
+
+ if ((node = mxmlFindElement(node, node, element, NULL, NULL,
+ descend)) == NULL)
+ return (NULL);
+ }
+
+ /*
+ * If we get this far, return the node or its first child...
+ */
+
+ if (node->child && node->child->type != MXML_ELEMENT)
+ return (node->child);
+ else
+ return (node);
+}
+
+
+/*
+ * 'mxmlWalkNext()' - Walk to the next logical node in the tree.
+ *
+ * The descend argument controls whether the first child is considered
+ * to be the next node. The top node argument constrains the walk to
+ * the node's children.
+ */
+
+mxml_node_t * /* O - Next node or NULL */
+mxmlWalkNext(mxml_node_t *node, /* I - Current node */
+ mxml_node_t *top, /* I - Top node */
+ int descend) /* I - Descend into tree - MXML_DESCEND, MXML_NO_DESCEND, or MXML_DESCEND_FIRST */
+{
+ if (!node)
+ return (NULL);
+ else if (node->child && descend)
+ return (node->child);
+ else if (node == top)
+ return (NULL);
+ else if (node->next)
+ return (node->next);
+ else if (node->parent && node->parent != top)
+ {
+ node = node->parent;
+
+ while (!node->next)
+ if (node->parent == top || !node->parent)
+ return (NULL);
+ else
+ node = node->parent;
+
+ return (node->next);
+ }
+ else
+ return (NULL);
+}
+
+
+/*
+ * 'mxmlWalkPrev()' - Walk to the previous logical node in the tree.
+ *
+ * The descend argument controls whether the previous node's last child
+ * is considered to be the previous node. The top node argument constrains
+ * the walk to the node's children.
+ */
+
+mxml_node_t * /* O - Previous node or NULL */
+mxmlWalkPrev(mxml_node_t *node, /* I - Current node */
+ mxml_node_t *top, /* I - Top node */
+ int descend) /* I - Descend into tree - MXML_DESCEND, MXML_NO_DESCEND, or MXML_DESCEND_FIRST */
+{
+ if (!node || node == top)
+ return (NULL);
+ else if (node->prev)
+ {
+ if (node->prev->last_child && descend)
+ {
+ /*
+ * Find the last child under the previous node...
+ */
+
+ node = node->prev->last_child;
+
+ while (node->last_child)
+ node = node->last_child;
+
+ return (node);
+ }
+ else
+ return (node->prev);
+ }
+ else if (node->parent != top)
+ return (node->parent);
+ else
+ return (NULL);
+}
+
+
+/*
+ * End of "$Id: mxml-search.c 451 2014-01-04 21:50:06Z msweet $".
+ */
diff --git a/emb/pastilda/lib/miniXML/mxml-set.c b/emb/pastilda/lib/miniXML/mxml-set.c
new file mode 100644
index 0000000..16d4bf1
--- /dev/null
+++ b/emb/pastilda/lib/miniXML/mxml-set.c
@@ -0,0 +1,337 @@
+/*
+ * "$Id: mxml-set.c 451 2014-01-04 21:50:06Z msweet $"
+ *
+ * Node set functions for Mini-XML, a small XML-like file parsing library.
+ *
+ * Copyright 2003-2014 by Michael R Sweet.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Michael R Sweet and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "COPYING"
+ * which should have been included with this file. If this file is
+ * missing or damaged, see the license at:
+ *
+ * http://www.msweet.org/projects.php/Mini-XML
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "config.h"
+#include "mxml.h"
+
+
+/*
+ * 'mxmlSetCDATA()' - Set the element name of a CDATA node.
+ *
+ * The node is not changed if it (or its first child) is not a CDATA element node.
+ *
+ * @since Mini-XML 2.3@
+ */
+
+int /* O - 0 on success, -1 on failure */
+mxmlSetCDATA(mxml_node_t *node, /* I - Node to set */
+ const char *data) /* I - New data string */
+{
+ /*
+ * Range check input...
+ */
+
+ if (node && node->type == MXML_ELEMENT &&
+ strncmp(node->value.element.name, "![CDATA[", 8) &&
+ node->child && node->child->type == MXML_ELEMENT &&
+ !strncmp(node->child->value.element.name, "![CDATA[", 8))
+ node = node->child;
+
+ if (!node || node->type != MXML_ELEMENT || !data ||
+ strncmp(node->value.element.name, "![CDATA[", 8))
+ return (-1);
+
+ /*
+ * Free any old element value and set the new value...
+ */
+
+ if (node->value.element.name)
+ free(node->value.element.name);
+
+ node->value.element.name = _mxml_strdupf("![CDATA[%s]]", data);
+
+ return (0);
+}
+
+
+/*
+ * 'mxmlSetCustom()' - Set the data and destructor of a custom data node.
+ *
+ * The node is not changed if it (or its first child) is not a custom node.
+ *
+ * @since Mini-XML 2.1@
+ */
+
+int /* O - 0 on success, -1 on failure */
+mxmlSetCustom(
+ mxml_node_t *node, /* I - Node to set */
+ void *data, /* I - New data pointer */
+ mxml_custom_destroy_cb_t destroy) /* I - New destructor function */
+{
+ /*
+ * Range check input...
+ */
+
+ if (node && node->type == MXML_ELEMENT &&
+ node->child && node->child->type == MXML_CUSTOM)
+ node = node->child;
+
+ if (!node || node->type != MXML_CUSTOM)
+ return (-1);
+
+ /*
+ * Free any old element value and set the new value...
+ */
+
+ if (node->value.custom.data && node->value.custom.destroy)
+ (*(node->value.custom.destroy))(node->value.custom.data);
+
+ node->value.custom.data = data;
+ node->value.custom.destroy = destroy;
+
+ return (0);
+}
+
+
+/*
+ * 'mxmlSetElement()' - Set the name of an element node.
+ *
+ * The node is not changed if it is not an element node.
+ */
+
+int /* O - 0 on success, -1 on failure */
+mxmlSetElement(mxml_node_t *node, /* I - Node to set */
+ const char *name) /* I - New name string */
+{
+ /*
+ * Range check input...
+ */
+
+ if (!node || node->type != MXML_ELEMENT || !name)
+ return (-1);
+
+ /*
+ * Free any old element value and set the new value...
+ */
+
+ if (node->value.element.name)
+ free(node->value.element.name);
+
+ node->value.element.name = strdup(name);
+
+ return (0);
+}
+
+
+/*
+ * 'mxmlSetInteger()' - Set the value of an integer node.
+ *
+ * The node is not changed if it (or its first child) is not an integer node.
+ */
+
+int /* O - 0 on success, -1 on failure */
+mxmlSetInteger(mxml_node_t *node, /* I - Node to set */
+ int integer) /* I - Integer value */
+{
+ /*
+ * Range check input...
+ */
+
+ if (node && node->type == MXML_ELEMENT &&
+ node->child && node->child->type == MXML_INTEGER)
+ node = node->child;
+
+ if (!node || node->type != MXML_INTEGER)
+ return (-1);
+
+ /*
+ * Set the new value and return...
+ */
+
+ node->value.integer = integer;
+
+ return (0);
+}
+
+
+/*
+ * 'mxmlSetOpaque()' - Set the value of an opaque node.
+ *
+ * The node is not changed if it (or its first child) is not an opaque node.
+ */
+
+int /* O - 0 on success, -1 on failure */
+mxmlSetOpaque(mxml_node_t *node, /* I - Node to set */
+ const char *opaque) /* I - Opaque string */
+{
+ /*
+ * Range check input...
+ */
+
+ if (node && node->type == MXML_ELEMENT &&
+ node->child && node->child->type == MXML_OPAQUE)
+ node = node->child;
+
+ if (!node || node->type != MXML_OPAQUE || !opaque)
+ return (-1);
+
+ /*
+ * Free any old opaque value and set the new value...
+ */
+
+ if (node->value.opaque)
+ free(node->value.opaque);
+
+ node->value.opaque = strdup(opaque);
+
+ return (0);
+}
+
+
+/*
+ * 'mxmlSetReal()' - Set the value of a real number node.
+ *
+ * The node is not changed if it (or its first child) is not a real number node.
+ */
+
+int /* O - 0 on success, -1 on failure */
+mxmlSetReal(mxml_node_t *node, /* I - Node to set */
+ double real) /* I - Real number value */
+{
+ /*
+ * Range check input...
+ */
+
+ if (node && node->type == MXML_ELEMENT &&
+ node->child && node->child->type == MXML_REAL)
+ node = node->child;
+
+ if (!node || node->type != MXML_REAL)
+ return (-1);
+
+ /*
+ * Set the new value and return...
+ */
+
+ node->value.real = real;
+
+ return (0);
+}
+
+
+/*
+ * 'mxmlSetText()' - Set the value of a text node.
+ *
+ * The node is not changed if it (or its first child) is not a text node.
+ */
+
+int /* O - 0 on success, -1 on failure */
+mxmlSetText(mxml_node_t *node, /* I - Node to set */
+ int whitespace, /* I - 1 = leading whitespace, 0 = no whitespace */
+ const char *string) /* I - String */
+{
+ /*
+ * Range check input...
+ */
+
+ if (node && node->type == MXML_ELEMENT &&
+ node->child && node->child->type == MXML_TEXT)
+ node = node->child;
+
+ if (!node || node->type != MXML_TEXT || !string)
+ return (-1);
+
+ /*
+ * Free any old string value and set the new value...
+ */
+
+ if (node->value.text.string)
+ free(node->value.text.string);
+
+ node->value.text.whitespace = whitespace;
+ node->value.text.string = strdup(string);
+
+ return (0);
+}
+
+
+/*
+ * 'mxmlSetTextf()' - Set the value of a text node to a formatted string.
+ *
+ * The node is not changed if it (or its first child) is not a text node.
+ */
+
+int /* O - 0 on success, -1 on failure */
+mxmlSetTextf(mxml_node_t *node, /* I - Node to set */
+ int whitespace, /* I - 1 = leading whitespace, 0 = no whitespace */
+ const char *format, /* I - Printf-style format string */
+ ...) /* I - Additional arguments as needed */
+{
+ va_list ap; /* Pointer to arguments */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (node && node->type == MXML_ELEMENT &&
+ node->child && node->child->type == MXML_TEXT)
+ node = node->child;
+
+ if (!node || node->type != MXML_TEXT || !format)
+ return (-1);
+
+ /*
+ * Free any old string value and set the new value...
+ */
+
+ if (node->value.text.string)
+ free(node->value.text.string);
+
+ va_start(ap, format);
+
+ node->value.text.whitespace = whitespace;
+ node->value.text.string = _mxml_strdupf(format, ap);
+
+ va_end(ap);
+
+ return (0);
+}
+
+
+/*
+ * 'mxmlSetUserData()' - Set the user data pointer for a node.
+ *
+ * @since Mini-XML 2.7@
+ */
+
+int /* O - 0 on success, -1 on failure */
+mxmlSetUserData(mxml_node_t *node, /* I - Node to set */
+ void *data) /* I - User data pointer */
+{
+ /*
+ * Range check input...
+ */
+
+ if (!node)
+ return (-1);
+
+ /*
+ * Set the user data pointer and return...
+ */
+
+ node->user_data = data;
+ return (0);
+}
+
+
+/*
+ * End of "$Id: mxml-set.c 451 2014-01-04 21:50:06Z msweet $".
+ */
diff --git a/emb/pastilda/lib/miniXML/mxml-string.c b/emb/pastilda/lib/miniXML/mxml-string.c
new file mode 100644
index 0000000..9d5b58e
--- /dev/null
+++ b/emb/pastilda/lib/miniXML/mxml-string.c
@@ -0,0 +1,469 @@
+/*
+ * "$Id: mxml-string.c 454 2014-01-05 03:25:07Z msweet $"
+ *
+ * String functions for Mini-XML, a small XML-like file parsing library.
+ *
+ * Copyright 2003-2014 by Michael R Sweet.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Michael R Sweet and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "COPYING"
+ * which should have been included with this file. If this file is
+ * missing or damaged, see the license at:
+ *
+ * http://www.msweet.org/projects.php/Mini-XML
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "config.h"
+
+
+/*
+ * The va_copy macro is part of C99, but many compilers don't implement it.
+ * Provide a "direct assignment" implmentation when va_copy isn't defined...
+ */
+
+#ifndef va_copy
+# ifdef __va_copy
+# define va_copy(dst,src) __va_copy(dst,src)
+# else
+# define va_copy(dst,src) memcpy(&dst, src, sizeof(va_list))
+# endif /* __va_copy */
+#endif /* va_copy */
+
+
+#ifndef HAVE_SNPRINTF
+/*
+ * '_mxml_snprintf()' - Format a string.
+ */
+
+int /* O - Number of bytes formatted */
+_mxml_snprintf(char *buffer, /* I - Output buffer */
+ size_t bufsize, /* I - Size of output buffer */
+ const char *format, /* I - Printf-style format string */
+ ...) /* I - Additional arguments as needed */
+{
+ va_list ap; /* Argument list */
+ int bytes; /* Number of bytes formatted */
+
+
+ va_start(ap, format);
+ bytes = vsnprintf(buffer, bufsize, format, ap);
+ va_end(ap);
+
+ return (bytes);
+}
+#endif /* !HAVE_SNPRINTF */
+
+
+/*
+ * '_mxml_strdup()' - Duplicate a string.
+ */
+
+#ifndef HAVE_STRDUP
+char * /* O - New string pointer */
+_mxml_strdup(const char *s) /* I - String to duplicate */
+{
+ char *t; /* New string pointer */
+
+
+ if (s == NULL)
+ return (NULL);
+
+ if ((t = malloc(strlen(s) + 1)) == NULL)
+ return (NULL);
+
+ return (strcpy(t, s));
+}
+#endif /* !HAVE_STRDUP */
+
+
+/*
+ * '_mxml_strdupf()' - Format and duplicate a string.
+ */
+
+char * /* O - New string pointer */
+_mxml_strdupf(const char *format, /* I - Printf-style format string */
+ ...) /* I - Additional arguments as needed */
+{
+ va_list ap; /* Pointer to additional arguments */
+ char *s; /* Pointer to formatted string */
+
+
+ /*
+ * Get a pointer to the additional arguments, format the string,
+ * and return it...
+ */
+
+ va_start(ap, format);
+ s = _mxml_vstrdupf(format, ap);
+ va_end(ap);
+
+ return (s);
+}
+
+
+#ifndef HAVE_VSNPRINTF
+/*
+ * '_mxml_vsnprintf()' - Format a string into a fixed size buffer.
+ */
+
+int /* O - Number of bytes formatted */
+_mxml_vsnprintf(char *buffer, /* O - Output buffer */
+ size_t bufsize, /* O - Size of output buffer */
+ const char *format, /* I - Printf-style format string */
+ va_list ap) /* I - Pointer to additional arguments */
+{
+ char *bufptr, /* Pointer to position in buffer */
+ *bufend, /* Pointer to end of buffer */
+ sign, /* Sign of format width */
+ size, /* Size character (h, l, L) */
+ type; /* Format type character */
+ int width, /* Width of field */
+ prec; /* Number of characters of precision */
+ char tformat[100], /* Temporary format string for sprintf() */
+ *tptr, /* Pointer into temporary format */
+ temp[1024]; /* Buffer for formatted numbers */
+ char *s; /* Pointer to string */
+ int slen; /* Length of string */
+ int bytes; /* Total number of bytes needed */
+
+
+ /*
+ * Loop through the format string, formatting as needed...
+ */
+
+ bufptr = buffer;
+ bufend = buffer + bufsize - 1;
+ bytes = 0;
+
+ while (*format)
+ {
+ if (*format == '%')
+ {
+ tptr = tformat;
+ *tptr++ = *format++;
+
+ if (*format == '%')
+ {
+ if (bufptr && bufptr < bufend)
+ *bufptr++ = *format;
+ bytes ++;
+ format ++;
+ continue;
+ }
+ else if (strchr(" -+#\'", *format))
+ {
+ *tptr++ = *format;
+ sign = *format++;
+ }
+ else
+ sign = 0;
+
+ if (*format == '*')
+ {
+ /*
+ * Get width from argument...
+ */
+
+ format ++;
+ width = va_arg(ap, int);
+
+ snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", width);
+ tptr += strlen(tptr);
+ }
+ else
+ {
+ width = 0;
+
+ while (isdigit(*format & 255))
+ {
+ if (tptr < (tformat + sizeof(tformat) - 1))
+ *tptr++ = *format;
+
+ width = width * 10 + *format++ - '0';
+ }
+ }
+
+ if (*format == '.')
+ {
+ if (tptr < (tformat + sizeof(tformat) - 1))
+ *tptr++ = *format;
+
+ format ++;
+
+ if (*format == '*')
+ {
+ /*
+ * Get precision from argument...
+ */
+
+ format ++;
+ prec = va_arg(ap, int);
+
+ snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", prec);
+ tptr += strlen(tptr);
+ }
+ else
+ {
+ prec = 0;
+
+ while (isdigit(*format & 255))
+ {
+ if (tptr < (tformat + sizeof(tformat) - 1))
+ *tptr++ = *format;
+
+ prec = prec * 10 + *format++ - '0';
+ }
+ }
+ }
+ else
+ prec = -1;
+
+ if (*format == 'l' && format[1] == 'l')
+ {
+ size = 'L';
+
+ if (tptr < (tformat + sizeof(tformat) - 2))
+ {
+ *tptr++ = 'l';
+ *tptr++ = 'l';
+ }
+
+ format += 2;
+ }
+ else if (*format == 'h' || *format == 'l' || *format == 'L')
+ {
+ if (tptr < (tformat + sizeof(tformat) - 1))
+ *tptr++ = *format;
+
+ size = *format++;
+ }
+
+ if (!*format)
+ break;
+
+ if (tptr < (tformat + sizeof(tformat) - 1))
+ *tptr++ = *format;
+
+ type = *format++;
+ *tptr = '\0';
+
+ switch (type)
+ {
+ case 'E' : /* Floating point formats */
+ case 'G' :
+ case 'e' :
+ case 'f' :
+ case 'g' :
+ if ((width + 2) > sizeof(temp))
+ break;
+
+ sprintf(temp, tformat, va_arg(ap, double));
+
+ bytes += strlen(temp);
+
+ if (bufptr)
+ {
+ if ((bufptr + strlen(temp)) > bufend)
+ {
+ strncpy(bufptr, temp, (size_t)(bufend - bufptr));
+ bufptr = bufend;
+ }
+ else
+ {
+ strcpy(bufptr, temp);
+ bufptr += strlen(temp);
+ }
+ }
+ break;
+
+ case 'B' : /* Integer formats */
+ case 'X' :
+ case 'b' :
+ case 'd' :
+ case 'i' :
+ case 'o' :
+ case 'u' :
+ case 'x' :
+ if ((width + 2) > sizeof(temp))
+ break;
+
+#ifdef HAVE_LONG_LONG
+ if (size == 'L')
+ sprintf(temp, tformat, va_arg(ap, long long));
+ else
+#endif /* HAVE_LONG_LONG */
+ sprintf(temp, tformat, va_arg(ap, int));
+
+ bytes += strlen(temp);
+
+ if (bufptr)
+ {
+ if ((bufptr + strlen(temp)) > bufend)
+ {
+ strncpy(bufptr, temp, (size_t)(bufend - bufptr));
+ bufptr = bufend;
+ }
+ else
+ {
+ strcpy(bufptr, temp);
+ bufptr += strlen(temp);
+ }
+ }
+ break;
+
+ case 'p' : /* Pointer value */
+ if ((width + 2) > sizeof(temp))
+ break;
+
+ sprintf(temp, tformat, va_arg(ap, void *));
+
+ bytes += strlen(temp);
+
+ if (bufptr)
+ {
+ if ((bufptr + strlen(temp)) > bufend)
+ {
+ strncpy(bufptr, temp, (size_t)(bufend - bufptr));
+ bufptr = bufend;
+ }
+ else
+ {
+ strcpy(bufptr, temp);
+ bufptr += strlen(temp);
+ }
+ }
+ break;
+
+ case 'c' : /* Character or character array */
+ bytes += width;
+
+ if (bufptr)
+ {
+ if (width <= 1)
+ *bufptr++ = va_arg(ap, int);
+ else
+ {
+ if ((bufptr + width) > bufend)
+ width = bufend - bufptr;
+
+ memcpy(bufptr, va_arg(ap, char *), (size_t)width);
+ bufptr += width;
+ }
+ }
+ break;
+
+ case 's' : /* String */
+ if ((s = va_arg(ap, char *)) == NULL)
+ s = "(null)";
+
+ slen = strlen(s);
+ if (slen > width && prec != width)
+ width = slen;
+
+ bytes += width;
+
+ if (bufptr)
+ {
+ if ((bufptr + width) > bufend)
+ width = bufend - bufptr;
+
+ if (slen > width)
+ slen = width;
+
+ if (sign == '-')
+ {
+ strncpy(bufptr, s, (size_t)slen);
+ memset(bufptr + slen, ' ', (size_t)(width - slen));
+ }
+ else
+ {
+ memset(bufptr, ' ', (size_t)(width - slen));
+ strncpy(bufptr + width - slen, s, (size_t)slen);
+ }
+
+ bufptr += width;
+ }
+ break;
+
+ case 'n' : /* Output number of chars so far */
+ *(va_arg(ap, int *)) = bytes;
+ break;
+ }
+ }
+ else
+ {
+ bytes ++;
+
+ if (bufptr && bufptr < bufend)
+ *bufptr++ = *format;
+
+ format ++;
+ }
+ }
+
+ /*
+ * Nul-terminate the string and return the number of characters needed.
+ */
+
+ *bufptr = '\0';
+
+ return (bytes);
+}
+#endif /* !HAVE_VSNPRINTF */
+
+
+/*
+ * '_mxml_vstrdupf()' - Format and duplicate a string.
+ */
+
+char * /* O - New string pointer */
+_mxml_vstrdupf(const char *format, /* I - Printf-style format string */
+ va_list ap) /* I - Pointer to additional arguments */
+{
+ int bytes; /* Number of bytes required */
+ char *buffer, /* String buffer */
+ temp[256]; /* Small buffer for first vsnprintf */
+ va_list apcopy; /* Copy of argument list */
+
+
+ /*
+ * First format with a tiny buffer; this will tell us how many bytes are
+ * needed...
+ */
+
+ va_copy(apcopy, ap);
+ bytes = vsnprintf(temp, sizeof(temp), format, apcopy);
+
+ if (bytes < sizeof(temp))
+ {
+ /*
+ * Hey, the formatted string fits in the tiny buffer, so just dup that...
+ */
+
+ return (strdup(temp));
+ }
+
+ /*
+ * Allocate memory for the whole thing and reformat to the new, larger
+ * buffer...
+ */
+
+ if ((buffer = calloc(1, bytes + 1)) != NULL)
+ vsnprintf(buffer, bytes + 1, format, ap);
+
+ /*
+ * Return the new string...
+ */
+
+ return (buffer);
+}
+
+
+/*
+ * End of "$Id: mxml-string.c 454 2014-01-05 03:25:07Z msweet $".
+ */
diff --git a/emb/pastilda/lib/miniXML/mxml.h b/emb/pastilda/lib/miniXML/mxml.h
new file mode 100644
index 0000000..bb48df7
--- /dev/null
+++ b/emb/pastilda/lib/miniXML/mxml.h
@@ -0,0 +1,332 @@
+/*
+ * "$Id: mxml.h 464 2016-06-12 21:16:14Z msweet $"
+ *
+ * Header file for Mini-XML, a small XML-like file parsing library.
+ *
+ * Copyright 2003-2016 by Michael R Sweet.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Michael R Sweet and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "COPYING"
+ * which should have been included with this file. If this file is
+ * missing or damaged, see the license at:
+ *
+ * http://www.msweet.org/projects.php/Mini-XML
+ */
+
+/*
+ * Prevent multiple inclusion...
+ */
+
+#ifndef _mxml_h_
+# define _mxml_h_
+
+/*
+ * Include necessary headers...
+ */
+
+# include <stdio.h>
+# include <stdlib.h>
+# include <string.h>
+# include <ctype.h>
+# include <errno.h>
+
+
+/*
+ * Constants...
+ */
+
+# define MXML_MAJOR_VERSION 2 /* Major version number */
+# define MXML_MINOR_VERSION 10 /* Minor version number */
+
+# define MXML_TAB 8 /* Tabs every N columns */
+
+# define MXML_NO_CALLBACK 0 /* Don't use a type callback */
+# define MXML_INTEGER_CALLBACK mxml_integer_cb
+ /* Treat all data as integers */
+# define MXML_OPAQUE_CALLBACK mxml_opaque_cb
+ /* Treat all data as opaque */
+# define MXML_REAL_CALLBACK mxml_real_cb
+ /* Treat all data as real numbers */
+# define MXML_TEXT_CALLBACK 0 /* Treat all data as text */
+# define MXML_IGNORE_CALLBACK mxml_ignore_cb
+ /* Ignore all non-element content */
+
+# define MXML_NO_PARENT 0 /* No parent for the node */
+
+# define MXML_DESCEND 1 /* Descend when finding/walking */
+# define MXML_NO_DESCEND 0 /* Don't descend when finding/walking */
+# define MXML_DESCEND_FIRST -1 /* Descend for first find */
+
+# define MXML_WS_BEFORE_OPEN 0 /* Callback for before open tag */
+# define MXML_WS_AFTER_OPEN 1 /* Callback for after open tag */
+# define MXML_WS_BEFORE_CLOSE 2 /* Callback for before close tag */
+# define MXML_WS_AFTER_CLOSE 3 /* Callback for after close tag */
+
+# define MXML_ADD_BEFORE 0 /* Add node before specified node */
+# define MXML_ADD_AFTER 1 /* Add node after specified node */
+# define MXML_ADD_TO_PARENT NULL /* Add node relative to parent */
+
+
+/*
+ * Data types...
+ */
+
+typedef enum mxml_sax_event_e /**** SAX event type. ****/
+{
+ MXML_SAX_CDATA, /* CDATA node */
+ MXML_SAX_COMMENT, /* Comment node */
+ MXML_SAX_DATA, /* Data node */
+ MXML_SAX_DIRECTIVE, /* Processing directive node */
+ MXML_SAX_ELEMENT_CLOSE, /* Element closed */
+ MXML_SAX_ELEMENT_OPEN /* Element opened */
+} mxml_sax_event_t;
+
+typedef enum mxml_type_e /**** The XML node type. ****/
+{
+ MXML_IGNORE = -1, /* Ignore/throw away node @since Mini-XML 2.3@ */
+ MXML_ELEMENT, /* XML element with attributes */
+ MXML_INTEGER, /* Integer value */
+ MXML_OPAQUE, /* Opaque string */
+ MXML_REAL, /* Real value */
+ MXML_TEXT, /* Text fragment */
+ MXML_CUSTOM /* Custom data @since Mini-XML 2.1@ */
+} mxml_type_t;
+
+typedef void (*mxml_custom_destroy_cb_t)(void *);
+ /**** Custom data destructor ****/
+
+typedef void (*mxml_error_cb_t)(const char *);
+ /**** Error callback function ****/
+
+typedef struct mxml_attr_s /**** An XML element attribute value. @private@ ****/
+{
+ char *name; /* Attribute name */
+ char *value; /* Attribute value */
+} mxml_attr_t;
+
+typedef struct mxml_element_s /**** An XML element value. @private@ ****/
+{
+ char *name; /* Name of element */
+ int num_attrs; /* Number of attributes */
+ mxml_attr_t *attrs; /* Attributes */
+} mxml_element_t;
+
+typedef struct mxml_text_s /**** An XML text value. @private@ ****/
+{
+ int whitespace; /* Leading whitespace? */
+ char *string; /* Fragment string */
+} mxml_text_t;
+
+typedef struct mxml_custom_s /**** An XML custom value. @private@ ****/
+{
+ void *data; /* Pointer to (allocated) custom data */
+ mxml_custom_destroy_cb_t destroy; /* Pointer to destructor function */
+} mxml_custom_t;
+
+typedef union mxml_value_u /**** An XML node value. @private@ ****/
+{
+ mxml_element_t element; /* Element */
+ int integer; /* Integer number */
+ char *opaque; /* Opaque string */
+ double real; /* Real number */
+ mxml_text_t text; /* Text fragment */
+ mxml_custom_t custom; /* Custom data @since Mini-XML 2.1@ */
+} mxml_value_t;
+
+struct mxml_node_s /**** An XML node. @private@ ****/
+{
+ mxml_type_t type; /* Node type */
+ struct mxml_node_s *next; /* Next node under same parent */
+ struct mxml_node_s *prev; /* Previous node under same parent */
+ struct mxml_node_s *parent; /* Parent node */
+ struct mxml_node_s *child; /* First child node */
+ struct mxml_node_s *last_child; /* Last child node */
+ mxml_value_t value; /* Node value */
+ int ref_count; /* Use count */
+ void *user_data; /* User data */
+};
+
+typedef struct mxml_node_s mxml_node_t; /**** An XML node. ****/
+
+struct mxml_index_s /**** An XML node index. @private@ ****/
+{
+ char *attr; /* Attribute used for indexing or NULL */
+ int num_nodes; /* Number of nodes in index */
+ int alloc_nodes; /* Allocated nodes in index */
+ int cur_node; /* Current node */
+ mxml_node_t **nodes; /* Node array */
+};
+
+typedef struct mxml_index_s mxml_index_t;
+ /**** An XML node index. ****/
+
+typedef int (*mxml_custom_load_cb_t)(mxml_node_t *, const char *);
+ /**** Custom data load callback function ****/
+
+typedef char *(*mxml_custom_save_cb_t)(mxml_node_t *);
+ /**** Custom data save callback function ****/
+
+typedef int (*mxml_entity_cb_t)(const char *);
+ /**** Entity callback function */
+
+typedef mxml_type_t (*mxml_load_cb_t)(mxml_node_t *);
+ /**** Load callback function ****/
+
+typedef const char *(*mxml_save_cb_t)(mxml_node_t *, int);
+ /**** Save callback function ****/
+
+typedef void (*mxml_sax_cb_t)(mxml_node_t *, mxml_sax_event_t, void *);
+ /**** SAX callback function ****/
+
+
+/*
+ * C++ support...
+ */
+
+# ifdef __cplusplus
+extern "C" {
+# endif /* __cplusplus */
+
+/*
+ * Prototypes...
+ */
+
+extern void mxmlAdd(mxml_node_t *parent, int where,
+ mxml_node_t *child, mxml_node_t *node);
+extern void mxmlDelete(mxml_node_t *node);
+extern void mxmlElementDeleteAttr(mxml_node_t *node,
+ const char *name);
+extern const char *mxmlElementGetAttr(mxml_node_t *node, const char *name);
+extern void mxmlElementSetAttr(mxml_node_t *node, const char *name,
+ const char *value);
+extern void mxmlElementSetAttrf(mxml_node_t *node, const char *name,
+ const char *format, ...)
+# ifdef __GNUC__
+__attribute__ ((__format__ (__printf__, 3, 4)))
+# endif /* __GNUC__ */
+;
+extern int mxmlEntityAddCallback(mxml_entity_cb_t cb);
+extern const char *mxmlEntityGetName(int val);
+extern int mxmlEntityGetValue(const char *name);
+extern void mxmlEntityRemoveCallback(mxml_entity_cb_t cb);
+extern mxml_node_t *mxmlFindElement(mxml_node_t *node, mxml_node_t *top,
+ const char *name, const char *attr,
+ const char *value, int descend);
+extern mxml_node_t *mxmlFindPath(mxml_node_t *node, const char *path);
+extern const char *mxmlGetCDATA(mxml_node_t *node);
+extern const void *mxmlGetCustom(mxml_node_t *node);
+extern const char *mxmlGetElement(mxml_node_t *node);
+extern mxml_node_t *mxmlGetFirstChild(mxml_node_t *node);
+extern int mxmlGetInteger(mxml_node_t *node);
+extern mxml_node_t *mxmlGetLastChild(mxml_node_t *node);
+extern mxml_node_t *mxmlGetNextSibling(mxml_node_t *node);
+extern const char *mxmlGetOpaque(mxml_node_t *node);
+extern mxml_node_t *mxmlGetParent(mxml_node_t *node);
+extern mxml_node_t *mxmlGetPrevSibling(mxml_node_t *node);
+extern double mxmlGetReal(mxml_node_t *node);
+extern int mxmlGetRefCount(mxml_node_t *node);
+extern const char *mxmlGetText(mxml_node_t *node, int *whitespace);
+extern mxml_type_t mxmlGetType(mxml_node_t *node);
+extern void *mxmlGetUserData(mxml_node_t *node);
+extern void mxmlIndexDelete(mxml_index_t *ind);
+extern mxml_node_t *mxmlIndexEnum(mxml_index_t *ind);
+extern mxml_node_t *mxmlIndexFind(mxml_index_t *ind,
+ const char *element,
+ const char *value);
+extern int mxmlIndexGetCount(mxml_index_t *ind);
+extern mxml_index_t *mxmlIndexNew(mxml_node_t *node, const char *element,
+ const char *attr);
+extern mxml_node_t *mxmlIndexReset(mxml_index_t *ind);
+extern mxml_node_t *mxmlLoadFd(mxml_node_t *top, int fd,
+ mxml_type_t (*cb)(mxml_node_t *));
+extern mxml_node_t *mxmlLoadFile(mxml_node_t *top, FILE *fp,
+ mxml_type_t (*cb)(mxml_node_t *));
+extern mxml_node_t *mxmlLoadString(mxml_node_t *top, const char *s,
+ mxml_type_t (*cb)(mxml_node_t *));
+extern mxml_node_t *mxmlNewCDATA(mxml_node_t *parent, const char *string);
+extern mxml_node_t *mxmlNewCustom(mxml_node_t *parent, void *data,
+ mxml_custom_destroy_cb_t destroy);
+extern mxml_node_t *mxmlNewElement(mxml_node_t *parent, const char *name);
+extern mxml_node_t *mxmlNewInteger(mxml_node_t *parent, int integer);
+extern mxml_node_t *mxmlNewOpaque(mxml_node_t *parent, const char *opaque);
+extern mxml_node_t *mxmlNewReal(mxml_node_t *parent, double real);
+extern mxml_node_t *mxmlNewText(mxml_node_t *parent, int whitespace,
+ const char *string);
+extern mxml_node_t *mxmlNewTextf(mxml_node_t *parent, int whitespace,
+ const char *format, ...)
+# ifdef __GNUC__
+__attribute__ ((__format__ (__printf__, 3, 4)))
+# endif /* __GNUC__ */
+;
+extern mxml_node_t *mxmlNewXML(const char *version);
+extern int mxmlRelease(mxml_node_t *node);
+extern void mxmlRemove(mxml_node_t *node);
+extern int mxmlRetain(mxml_node_t *node);
+extern char *mxmlSaveAllocString(mxml_node_t *node,
+ mxml_save_cb_t cb);
+extern int mxmlSaveFd(mxml_node_t *node, int fd,
+ mxml_save_cb_t cb);
+extern int mxmlSaveFile(mxml_node_t *node, FILE *fp,
+ mxml_save_cb_t cb);
+extern int mxmlSaveString(mxml_node_t *node, char *buffer,
+ int bufsize, mxml_save_cb_t cb);
+extern mxml_node_t *mxmlSAXLoadFd(mxml_node_t *top, int fd,
+ mxml_type_t (*cb)(mxml_node_t *),
+ mxml_sax_cb_t sax, void *sax_data);
+extern mxml_node_t *mxmlSAXLoadFile(mxml_node_t *top, FILE *fp,
+ mxml_type_t (*cb)(mxml_node_t *),
+ mxml_sax_cb_t sax, void *sax_data);
+extern mxml_node_t *mxmlSAXLoadString(mxml_node_t *top, const char *s,
+ mxml_type_t (*cb)(mxml_node_t *),
+ mxml_sax_cb_t sax, void *sax_data);
+extern int mxmlSetCDATA(mxml_node_t *node, const char *data);
+extern int mxmlSetCustom(mxml_node_t *node, void *data,
+ mxml_custom_destroy_cb_t destroy);
+extern void mxmlSetCustomHandlers(mxml_custom_load_cb_t load,
+ mxml_custom_save_cb_t save);
+extern int mxmlSetElement(mxml_node_t *node, const char *name);
+extern void mxmlSetErrorCallback(mxml_error_cb_t cb);
+extern int mxmlSetInteger(mxml_node_t *node, int integer);
+extern int mxmlSetOpaque(mxml_node_t *node, const char *opaque);
+extern int mxmlSetReal(mxml_node_t *node, double real);
+extern int mxmlSetText(mxml_node_t *node, int whitespace,
+ const char *string);
+extern int mxmlSetTextf(mxml_node_t *node, int whitespace,
+ const char *format, ...)
+# ifdef __GNUC__
+__attribute__ ((__format__ (__printf__, 3, 4)))
+# endif /* __GNUC__ */
+;
+extern int mxmlSetUserData(mxml_node_t *node, void *data);
+extern void mxmlSetWrapMargin(int column);
+extern mxml_node_t *mxmlWalkNext(mxml_node_t *node, mxml_node_t *top,
+ int descend);
+extern mxml_node_t *mxmlWalkPrev(mxml_node_t *node, mxml_node_t *top,
+ int descend);
+
+
+/*
+ * Semi-private functions...
+ */
+
+extern void mxml_error(const char *format, ...);
+extern mxml_type_t mxml_ignore_cb(mxml_node_t *node);
+extern mxml_type_t mxml_integer_cb(mxml_node_t *node);
+extern mxml_type_t mxml_opaque_cb(mxml_node_t *node);
+extern mxml_type_t mxml_real_cb(mxml_node_t *node);
+
+
+/*
+ * C++ support...
+ */
+
+# ifdef __cplusplus
+}
+# endif /* __cplusplus */
+#endif /* !_mxml_h_ */
+
+
+/*
+ * End of "$Id: mxml.h 464 2016-06-12 21:16:14Z msweet $".
+ */
diff --git a/emb/pastilda/menu/KeyboardLikeInput.hpp b/emb/pastilda/menu/KeyboardLikeInput.hpp
new file mode 100644
index 0000000..53cfff3
--- /dev/null
+++ b/emb/pastilda/menu/KeyboardLikeInput.hpp
@@ -0,0 +1,201 @@
+/*
+ * This file is part of the pastilda project.
+ * hosted at http://github.com/thirdpin/pastilda
+ *
+ * Copyright (C) 2016 Third Pin LLC
+ *
+ * Written by:
+ * Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ * Dmitrii Lisin <mrlisdim@ya.ru>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MENU_KEYBOARDLIKEINPUT_HPP_
+#define MENU_KEYBOARDLIKEINPUT_HPP_
+
+#include <cstddef>
+#include <cstring>
+
+#include <usb_package.h>
+#include <menu/UsbPackageFactory.h>
+
+namespace Logic {
+
+using namespace UsbPackages;
+
+using std::size_t;
+using std::memcmp;
+
+
+// DESCRIPTION
+// Keyboard have strange logic. If you press keys 1, 2 and 3 simultaneously
+// then you will see input package like {0, 0, 0, 1, 2, 3, 0, 0, 0}. But if you
+// send 1, 2 and 3 one by one very fast, then you'll see packages like:
+// 1. {0, 0, 0, 1, 0, 0, 0, 0, 0}
+// 2. {0, 0, 0, 1, 2, 0, 0, 0, 0}
+// 3. {0, 0, 0, 2, 3, 0, 0, 0, 0}
+// 4. {0, 0, 0, 3, 0, 0, 0, 0, 0}
+// So this class converts this strange logic to linear.
+
+template<typename T>
+class KeyboardLikeInput {
+public:
+ using KeyBuffer = T;
+
+ explicit KeyboardLikeInput(KeyBuffer* buffer
+#ifdef DEBUG
+ , PackageFactory* f
+#endif
+ );
+ ~KeyboardLikeInput();
+
+ void process(UsbPackageConst* packagePtr);
+
+private:
+#ifdef DEBUG
+ PackageFactory* _f;
+#endif
+
+ KeyBuffer* _buffer;
+
+ UsbPackageConst* _inputPackagePtr;
+ UsbPackage _lastPackage;
+
+ bool _ignoreKeys;
+
+ void _storeKey(Key& key);
+ void _storeInputPackage();
+ void _storeInputPackageSeries();
+
+ void _resetInput();
+};
+
+template<typename T>
+KeyboardLikeInput<T>::KeyboardLikeInput(KeyBuffer* buffer
+#ifdef DEBUG
+ , PackageFactory* f
+#endif
+) :
+#ifdef DEBUG
+ _f(f),
+#endif
+ _buffer(buffer),
+ _inputPackagePtr(nullptr),
+ _ignoreKeys(false)
+{
+ _resetInput();
+}
+
+template<typename T>
+KeyboardLikeInput<T>::~KeyboardLikeInput()
+{ }
+
+template<typename T>
+void KeyboardLikeInput<T>::process(UsbPackages::UsbPackageConst* packagePtr)
+{
+ _inputPackagePtr = packagePtr;
+
+ if (*_inputPackagePtr != ZERO_PACKAGE) {
+ if (_lastPackage == ZERO_PACKAGE) {
+ _storeInputPackage();
+#ifdef DEBUG
+ _f->processData(" s+", 3);
+ _f->generatePackage((uint8_t*)_inputPackagePtr);
+#endif
+ }
+ else {
+ if (_inputPackagePtr->key[2] != UsbKey::NOT_A_KEY) {
+ _ignoreKeys = true;
+ }
+
+ if (_ignoreKeys == false) {
+ _storeInputPackageSeries();
+ }
+#ifdef DEBUG
+ _f->processData(" o+", 3);
+ _f->generatePackage((uint8_t*)_inputPackagePtr);
+#endif
+ }
+ }
+ else {
+ _resetInput();
+ }
+
+ _lastPackage = *_inputPackagePtr;
+}
+
+template<typename T>
+void KeyboardLikeInput<T>::_storeInputPackage()
+{
+ for (size_t i = 0;
+ i < UsbPackages::USB_PACKAGE_KEY_FIELDS_LENGTH;
+ ++i)
+ {
+ Key key(_inputPackagePtr->key[i], _inputPackagePtr->special);
+ _storeKey(key);
+ }
+}
+
+template<typename T>
+void KeyboardLikeInput<T>::_storeInputPackageSeries()
+{
+ for (size_t i = 0;
+ i < UsbPackages::USB_PACKAGE_KEY_FIELDS_LENGTH;
+ ++i)
+ {
+ Key key(_inputPackagePtr->key[i], _inputPackagePtr->special);
+ AsciiCode compareValue = static_cast<AsciiCode>(_buffer->back());
+ AsciiCodeType compareValueCode = _buffer->back();
+
+ if (isAsciiShifted(compareValue)) {
+ compareValueCode =
+ static_cast<AsciiCodeType>(
+ getAsciiBackShifted(compareValue)
+ );
+ }
+
+ if (key.getAsciiCode() != compareValueCode) {
+ _storeKey(key);
+ }
+ }
+}
+
+template<typename T>
+void KeyboardLikeInput<T>::_storeKey(Key& key)
+{
+ if (key == UsbKey::KEY_BACKSPACE) {
+ if (_buffer->empty() == false) {
+ _buffer->pop_back();
+ }
+ }
+ else if (key.isControl() == false &&
+ key.getUsbKey() != UsbKey::NOT_A_KEY)
+ {
+ if (_buffer->full() == false) {
+ _buffer->push_back(key.getAsciiCode());
+ }
+ }
+}
+
+template<typename T>
+void KeyboardLikeInput<T>::_resetInput()
+{
+ _lastPackage = ZERO_PACKAGE;
+ _ignoreKeys = false;
+}
+
+} /* namespace Logic */
+
+#endif /* MENU_KEYBOARDLIKEINPUT_HPP_ */
diff --git a/emb/pastilda/menu/Menu.hpp b/emb/pastilda/menu/Menu.hpp
new file mode 100644
index 0000000..8447449
--- /dev/null
+++ b/emb/pastilda/menu/Menu.hpp
@@ -0,0 +1,183 @@
+/*
+ * This file is part of the pastilda project.
+ * hosted at http://github.com/thirdpin/pastilda
+ *
+ * Copyright (C) 2016 Third Pin LLC
+ *
+ * Written by:
+ * Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ * Dmitrii Lisin <mrlisdim@ya.ru>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MENU_H_
+#define MENU_H_
+
+#include <keys/Key.h>
+#include <database/DbEntry.h>
+#include <Tree.hpp>
+
+template <std::size_t COUNT_OF_MENU_POINTS>
+class Menu {
+public:
+ static constexpr std::size_t COUNT_OF_POINTS = COUNT_OF_MENU_POINTS;
+
+ using TreeT = Tree<COUNT_OF_POINTS, DB::Entry>;
+ using TreePtr = TreeT*;
+
+ using MenuPoint = typename TreeT::TreeNodePtr;
+
+ using ContainerT = typename TreeT::ContainerT;
+
+ template<typename T>
+ struct PointDescr {
+ using CallbackT = T;
+
+ const char* name;
+ size_t nameLength;
+ CallbackT callback;
+ };
+
+ void init(TreePtr tree) {
+ _tree = tree;
+ }
+ void processKey(Keys::Key key);
+ size_t search(DB::StringFieldConst& substring);
+
+ void moveTop();
+
+ ContainerT& getCurrentPointContainer();
+
+ Menu();
+ Menu(TreePtr tree);
+ ~Menu();
+
+private:
+ TreePtr _tree;
+
+ void _processEnterKey();
+};
+
+template<std::size_t COUNT_OF_MENU_POINTS>
+Menu<COUNT_OF_MENU_POINTS>::Menu():
+ _tree(nullptr)
+{ }
+
+template<std::size_t COUNT_OF_MENU_POINTS>
+Menu<COUNT_OF_MENU_POINTS>::Menu(TreePtr tree):
+ _tree(tree)
+{ }
+
+template<std::size_t COUNT_OF_MENU_POINTS>
+Menu<COUNT_OF_MENU_POINTS>::~Menu()
+{ }
+
+template<std::size_t COUNT_OF_MENU_POINTS>
+inline void Menu<COUNT_OF_MENU_POINTS>::moveTop()
+{
+ _tree->moveInHead(); // maximum top
+ _tree->moveMostLeft(); // maximum left
+}
+
+template<std::size_t COUNT_OF_MENU_POINTS>
+void Menu<COUNT_OF_MENU_POINTS>::processKey(Keys::Key key)
+{
+ using ControlKey = Keys::UsbKey;
+
+ if (key == ControlKey::KEY_UPARROW) {
+ _tree->moveLeft();
+ }
+ else if (key == ControlKey::KEY_DOWNARROW) {
+ _tree->moveRight();
+ }
+ else if (key == ControlKey::KEY_LEFTARROW) {
+ _tree->moveOut();
+ }
+ else if (key == ControlKey::KEY_RIGHTARROW) {
+ _tree->moveInto();
+ }
+ else if (key == ControlKey::KEY_ENTER) {
+ _processEnterKey();
+ }
+}
+
+template<std::size_t COUNT_OF_MENU_POINTS>
+typename Menu<COUNT_OF_MENU_POINTS>::ContainerT&
+Menu<COUNT_OF_MENU_POINTS>::getCurrentPointContainer()
+{
+ return _tree->getCurrentNode()->getContainer();
+}
+
+template<std::size_t COUNT_OF_MENU_POINTS>
+void Menu<COUNT_OF_MENU_POINTS>::_processEnterKey()
+{
+ MenuPoint currentPoint = _tree->getCurrentNode();
+ if (currentPoint->isEndNode()) {
+ currentPoint->call();
+ }
+ else {
+ _tree->moveInto();
+ }
+}
+
+template<std::size_t COUNT_OF_MENU_POINTS>
+size_t Menu<COUNT_OF_MENU_POINTS>::search(DB::StringFieldConst& substring)
+{
+ size_t pos = DB::StringField::npos;
+
+ // Remember last node
+ int32_t currentNodeNum = _tree->getCurrentChildNum();
+
+ _tree->moveMostLeft();
+
+ // Finding lambda
+ auto findSubstring = [&]() -> size_t {
+ DB::StringFieldConst& compareString =
+ _tree->getCurrentNode()->getContainer().getName();
+ pos = compareString.compare(0, substring.length(), substring);
+ };
+
+ // If found lambda
+ auto substringWasFound = [&]() -> bool {
+ return pos == 0;
+ };
+
+ // Trying to found something
+ while (_tree->isMostRight() == false) {
+ findSubstring();
+ if (substringWasFound()) {
+ break;
+ }
+ _tree->moveRight();
+ }
+
+ // Founding in last child
+ if (substringWasFound() == false) {
+ findSubstring();
+ }
+
+ // If found nothing, return to last node
+ if (substringWasFound() == false) {
+ _tree->moveMostLeft();
+ while (currentNodeNum > 0) {
+ currentNodeNum--;
+ _tree->moveRight();
+ }
+ }
+
+ return pos;
+}
+
+#endif /* MENU_H_ */
diff --git a/emb/pastilda/menu/TildaLogic.cpp b/emb/pastilda/menu/TildaLogic.cpp
new file mode 100644
index 0000000..a0e41ad
--- /dev/null
+++ b/emb/pastilda/menu/TildaLogic.cpp
@@ -0,0 +1,511 @@
+/*
+ * This file is part of the pastilda project.
+ * hosted at http://github.com/thirdpin/pastilda
+ *
+ * Copyright (C) 2016 Third Pin LLC
+ *
+ * Written by:
+ * Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ * Dmitrii Lisin <mrlisdim@ya.ru>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <cstring>
+#include <cstdio>
+
+#include <FastDelegate.h>
+
+#include "systick_ext.h"
+#include <keys/Key.h>
+
+#include <TildaLogic.h>
+
+using std::string;
+using std::size_t;
+
+using namespace Keys;
+using namespace DB;
+
+namespace fd = fastdelegate;
+
+namespace Logic {
+using namespace Logic::Private;
+
+TildaLogic::TildaLogic(UsbDequeStandart* deque,
+ const SpecialPoints& specialPoints):
+ _inputData(nullptr),
+ _inputDataLength(0),
+ _inputPackagePtr(&ZERO_PACKAGE),
+ _packageFactory(PackageFactory(deque)),
+ _db(nullptr),
+ _fixedMenuCbs(new FixedMenuCallbacks(this)),
+ _lastPackage(ZERO_PACKAGE),
+ _lastKeysBufferLen(0),
+ _keyboardInput(KeyboardLikeInput<KeyBuffer>(&_keysBuffer
+#ifdef DEBUG
+ , &_packageFactory
+#endif
+ ))
+{
+ _specialMenuPoints.formatFat = specialPoints.formatFat;
+
+ _init();
+}
+
+TildaLogic::~TildaLogic()
+{ }
+
+void TildaLogic::_init()
+{
+ _fixedMenu.settings = {
+ Strings::SETTINGS_POINT,
+ std::strlen(Strings::SETTINGS_POINT),
+ MenuTreeT::TreeNodeT::EMPTY_CALLBACK
+ };
+
+ _fixedMenu.exit = {
+ Strings::EXIT_POINT,
+ strlen(Strings::EXIT_POINT),
+ fd::MakeDelegate(_fixedMenuCbs, &FixedMenuCallbacks::exit)
+ };
+
+ _tildaKey = TILDA_MODE_KEY;
+ _tildaSeq.set(UsbSpecialKey::LEFT_CTRL);
+
+ _setState(State::PASSIVE_MODE);
+}
+
+void TildaLogic::_buildMenu()
+{
+ _db.init(_keepassReader.get_xml());
+
+ _menuTree.destroy();
+ _buildMenuTree();
+
+ _menu.init(&_menuTree);
+ _menu.moveTop();
+}
+
+void TildaLogic::_buildMenuTree()
+{
+ constexpr uint32_t startIndex = 0;
+ _buildTree(startIndex);
+
+ _menuTree.moveInHead();
+ _menuTree.moveMostRight();
+ _buildFixedMenu();
+}
+
+void TildaLogic::_buildTree(uint32_t index)
+{
+ _copyDbContainer(index++);
+
+ if (_db.isMostBottom() == false) {
+ _db.moveInto();
+
+ _menuTree.addChild();
+ _menuTree.moveInto();
+ _menuTree.moveMostRight();
+
+ _buildTree(index++);
+ }
+ else {
+ while (_db.isMostRight() == false) {
+ _db.moveRight();
+
+ _menuTree.moveOut();
+ if (_db.isMostTop()) {
+ _menuTree.addNeighbor();
+ _menuTree.moveRight();
+ }
+ else {
+ _menuTree.addChild();
+ _menuTree.moveInto();
+ _menuTree.moveMostRight();
+ }
+
+ _buildTree(index++);
+ }
+
+ _db.moveOut();
+ _menuTree.moveOut();
+ }
+}
+
+void TildaLogic::_buildFixedMenu()
+{
+ _menuTree.addNeighbor();
+ _menuTree.moveRight();
+ _addMenuPoint(_fixedMenu.settings);
+
+ // Add special menu points
+ _menuTree.addChild();
+ _menuTree.moveInto();
+ _addMenuPoint(_specialMenuPoints.formatFat);
+ _menuTree.getCurrentNode()->setCallback(
+ fd::MakeDelegate(_fixedMenuCbs, &FixedMenuCallbacks::formatFat)
+ );
+ // Another points
+ _menuTree.moveOut();
+
+ _menuTree.addNeighbor();
+ _menuTree.moveRight();
+ _addMenuPoint(_fixedMenu.exit);
+ _menuTree.getCurrentNode()->setCallback(
+ _fixedMenu.exit.callback
+ );
+}
+
+void TildaLogic::_copyDbContainer(uint32_t index)
+{
+ MenuTreeT::TreeNodePtr currentNode = _menuTree.getCurrentNode();
+ MenuTreeT::ContainerT& currentContainer = currentNode->getContainer();
+
+ const XmlTree::NodeStruct& srcNode = _db.getCurrentNodeInfo();
+
+ currentContainer.setIndex(index);
+ currentContainer.setName(srcNode.name.data(), srcNode.name.length());
+ currentContainer.setLogin(srcNode.login.data(), srcNode.login.length());
+ currentContainer.setPassword(srcNode.password.data(),
+ srcNode.password.length());
+ currentContainer.setType(srcNode.type.data(), srcNode.type.length());
+
+ if (_db.isEndNode()) {
+ currentNode->setCallback(
+ fd::MakeDelegate(
+ this,
+ &TildaLogic::_logInCallback
+ )
+ );
+ }
+}
+
+template<typename T>
+void TildaLogic::_addMenuPoint(T& point)
+{
+ MenuTreeT::TreeNodePtr node = _menuTree.getCurrentNode();
+ node->getContainer().setName(
+ reinterpret_cast<const StringFieldChar*>(
+ point.name
+ ),
+ point.nameLength
+ );
+}
+
+void TildaLogic::_logInCallback(MenuT::ContainerT& container)
+{
+ _packageFactory.generateClearSequence(container.getName().length());
+
+ // Login enter
+ _packageFactory.processData(container.getLogin());
+
+ // Switch field
+ StringFieldConst& type = container.getType();
+ if (type == Strings::FORM) {
+ _packageFactory.generateTabPackage();
+ }
+ else {
+ _packageFactory.generateEnterPackage();
+ delay_ms(800); // Wait console reaction
+ }
+
+ // Password enter
+ _packageFactory.processData(container.getPassword());
+
+ // Press "Enter"
+ _packageFactory.generateEnterPackage();
+
+ _setState(State::MENU_MODE_END);
+}
+
+void TildaLogic::process(DataBufferConst inputData, size_t inputDataLength)
+{
+ _inputData = inputData;
+ _inputDataLength = inputDataLength;
+ _inputPackagePtr = reinterpret_cast<UsbPackageConst*>(inputData);
+
+ switch (_currentState)
+ {
+ case State::PASSIVE_MODE:
+ _checkMode();
+ _redirectInput();
+ _lastPackage = *_inputPackagePtr;
+ break;
+
+ case State::ENTER_MASTER_PASSWORD:
+ _processMasterPassword();
+ break;
+
+ case State::MENU_MODE_START:
+ _sendMenuGreeting();
+ _setState(State::MENU_MODE);
+ break;
+
+ case State::MENU_MODE:
+ _processMenuMode();
+ _lastPackage = *_inputPackagePtr;
+ break;
+
+ default:
+ break;
+ }
+}
+
+void TildaLogic::_processMasterPassword()
+{
+ if (_inputPackagePtr->key[0] == UsbKey::KEY_ENTER) {
+ const char* passw = (const char*)_keysBuffer.data();
+ size_t passwLen = _keysBuffer.size();
+
+ _dbDecrypt(passw, passwLen);
+
+ _keysBuffer.resize(0);
+ _packageFactory.generateClearSequence(_lastKeysBufferLen);
+ _lastKeysBufferLen = 0;
+
+ if (_currentState == State::MASTER_PASSWORD_PASSED) {
+ _buildMenu();
+
+ _setState(State::MENU_MODE_START);
+ }
+ else {
+ _clearMsg(Strings::GREETING_TO_WRITE);
+
+ _sendMsg(_getDbErrorType());
+ delay_ms(WRONG_PASSWORD_DELAY);
+ _clearMsg(_getDbErrorType());
+
+ _setState(State::ENTER_MASTER_PASSWORD);
+
+ _sendMsg(Strings::GREETING_TO_WRITE);
+ }
+ }
+ else if (_inputPackagePtr->key[0] == UsbKey::KEY_ESCAPE) {
+ _packageFactory.generateClearSequence(_lastKeysBufferLen);
+ _lastKeysBufferLen = 0;
+
+ _clearMsg(Strings::GREETING_TO_WRITE);
+ _setState(State::PASSIVE_MODE);
+ }
+ else {
+ _keyboardInput.process(_inputPackagePtr);
+
+ int32_t newOutputLen =
+ (int32_t)_keysBuffer.size() - (int32_t)_lastKeysBufferLen;
+ if (newOutputLen > 0) {
+#ifdef DEBUG
+ _packageFactory.processData(" >", 2);
+ for (size_t i = _lastKeysBufferLen; i < _keysBuffer.size(); ++i) {
+ _packageFactory.processData((char*)&_keysBuffer[i], 1);
+ }
+#else
+ for (size_t i = 0; i < newOutputLen; ++i) {
+ _sendMsg(Strings::PASSWORD_SYMB);
+ }
+#endif
+ }
+ else {
+ _packageFactory.generateClearSequence(abs(newOutputLen));
+ _packageFactory.generateEmptyPackage();
+ }
+
+ _lastKeysBufferLen = _keysBuffer.size();
+ }
+}
+
+void TildaLogic::_dbDecrypt(const char* passwd, size_t len)
+{
+ using namespace KeepAss;
+
+ _keepassReader.set_password(passwd, len);
+
+ _dbState = _keepassReader.decrypt_database(KEEPASS_BASE_FILE);
+
+ if (_dbState == DecryptionResult::SUCCESS) {
+ _setState(State::MASTER_PASSWORD_PASSED);
+ }
+ else {
+ _setState(State::PASSIVE_MODE);
+ }
+}
+
+void TildaLogic::_redirectInput()
+{
+ _packageFactory.generatePackage(_inputData);
+}
+
+inline void TildaLogic::_checkMode()
+{
+ if (_inputPackagePtr->key[0] == UsbKey::NOT_A_KEY) {
+ if (_tildaKey == _lastPackage.key[0] &&
+ _tildaSeq == _lastPackage.special)
+ {
+ _switchMenuMode();
+ _lastPackage = ZERO_PACKAGE;
+
+ if (_currentState == State::MENU_MODE_START) {
+ _sendMsg(Strings::GREETING_TO_WRITE);
+
+ _setState(State::ENTER_MASTER_PASSWORD);
+ }
+ }
+ }
+}
+
+inline void TildaLogic::_sendMenuGreeting()
+{
+ _menu.moveTop();
+
+ _clearMsg(Strings::GREETING_TO_WRITE);
+ _packageFactory.processData(
+ _menu.getCurrentPointContainer().getName()
+ );
+}
+
+inline void TildaLogic::_switchMenuMode()
+{
+ _keysBuffer.resize(0);
+ if (_currentState == State::MENU_MODE ||
+ _currentState == State::MENU_MODE_END ||
+ _currentState == State::ENTER_MASTER_PASSWORD)
+ {
+ _setState(State::PASSIVE_MODE);
+ }
+ else {
+ _setState(State::MENU_MODE_START);
+ }
+}
+
+void TildaLogic::_processMenuMode()
+{
+ Key key {
+ _inputPackagePtr->key[0],
+ _inputPackagePtr->special
+ };
+
+ if (key == UsbKey::KEY_ESCAPE) {
+ _keysBuffer.resize(0);
+
+ StringFieldConst currentPoint =
+ _menu.getCurrentPointContainer().getName();
+ _packageFactory.generateClearSequence(currentPoint.length());
+ _setState(State::PASSIVE_MODE);
+ }
+ else if (key.isControl()) {
+ _keysBuffer.resize(0); // reset key buffer
+
+ StringFieldConst currentPoint =
+ _menu.getCurrentPointContainer().getName();
+
+ _menu.processKey(key);
+
+ StringFieldConst& newPoint =
+ _menu.getCurrentPointContainer().getName();
+
+ if (_currentState == State::MENU_MODE_END) {
+ _switchMenuMode();
+ _setState(State::PASSIVE_MODE);
+ }
+ else if (newPoint.compare(currentPoint) != 0) {
+ _packageFactory.generateClearSequence(currentPoint.length());
+ _packageFactory.processData(newPoint);
+ }
+ }
+ // TODO: place it into separate class, into Menu (probably)
+// else if (key != UsbKey::NOT_A_KEY) { // in search mode
+// _setState(State::SEARCH_MODE);
+// }
+}
+
+void TildaLogic::_searchMode()
+{
+ StringFieldConst currentPoint =
+ _menu.getCurrentPointContainer().getName();
+
+ size_t pos = _menu.search(
+ StringField(_keysBuffer.data(), _keysBuffer.size())
+ );
+
+ StringFieldConst& newPoint =
+ _menu.getCurrentPointContainer().getName();
+
+ bool pointChanged = newPoint.compare(currentPoint);
+
+ if (pos != StringField::npos && pointChanged) {
+ _packageFactory.generateClearSequence(currentPoint.length());
+ _packageFactory.processData(newPoint);
+ }
+}
+
+const char* TildaLogic::_getDbErrorType()
+{
+ using namespace KeepAss;
+
+ switch (_dbState) {
+ case DecryptionResult::CREDENTIALS_ERROR:
+ return Strings::CREDENTIALS_ERROR;
+ break;
+
+ case DecryptionResult::DATA_HASH_ERROR:
+ return Strings::DATA_HASH_ERROR;
+ break;
+
+ case DecryptionResult::DB_FILE_ERROR:
+ return Strings::DB_FILE_ERROR;
+ break;
+
+ case DecryptionResult::MASTER_KEY_ERROR:
+ return Strings::MASTER_KEY_ERROR;
+ break;
+
+ case DecryptionResult::SIGNATURE_ERROR:
+ return Strings::SIGNATURE_ERROR;
+ break;
+
+ default:
+ return Strings::PASSWORD_WRONG;
+ break;
+ }
+}
+
+void TildaLogic::_sendMsg(const char* msg)
+{
+ _packageFactory.processData(msg, std::strlen(msg));
+}
+
+void TildaLogic::_clearMsg(const char* msg)
+{
+ _packageFactory.generateClearSequence(strlen(msg));
+}
+
+namespace Private {
+ FixedMenuCallbacks::FixedMenuCallbacks(TildaLogic* logic) :
+ _logic(logic)
+ { }
+
+ void FixedMenuCallbacks::formatFat(TildaLogic::CallbackArg arg)
+ {
+ _logic->_specialMenuPoints.formatFat.callback();
+
+ _logic->_setState(TildaLogic::State::MENU_MODE_END);
+ }
+
+ void FixedMenuCallbacks::exit(TildaLogic::CallbackArg arg)
+ {
+ _logic->_setState(TildaLogic::State::MENU_MODE_END);
+ }
+}
+
+} // namespace Logic
diff --git a/emb/pastilda/menu/TildaLogic.h b/emb/pastilda/menu/TildaLogic.h
new file mode 100644
index 0000000..150808a
--- /dev/null
+++ b/emb/pastilda/menu/TildaLogic.h
@@ -0,0 +1,208 @@
+/*
+ * This file is part of the pastilda project.
+ * hosted at http://github.com/thirdpin/pastilda
+ *
+ * Copyright (C) 2016 Third Pin LLC
+ *
+ * Written by:
+ * Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ * Dmitrii Lisin <mrlisdim@ya.ru>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef TILDALOGIC_H_
+#define TILDALOGIC_H_
+
+#include <cstring>
+#include <etl/vector.h>
+
+#include <usb_deque.h>
+#include <keys/Key.h>
+#include <keepass/keepass_reader.h>
+#include <database/DbEntry.h>
+#include <database/xmltree/XmlTree.h>
+#include <KeyboardLikeInput.hpp>
+#include <Menu.hpp>
+#include <UsbPackageFactory.h>
+
+using std::size_t;
+using std::string;
+
+using namespace Keys;
+using namespace UsbPackages;
+
+namespace Logic {
+
+namespace Private {
+ class FixedMenuCallbacks;
+
+ namespace Strings {
+ // Messages
+ static constexpr const char* PASSWORD_WRONG = "Failed!\0";
+ static constexpr const char* GREETING_TO_WRITE = "Pass:\0";
+ static constexpr const char* PASSWORD_SYMB = "*\0";
+ // Menu point's names
+ static constexpr const char* SETTINGS_POINT = "Settings\0";
+ static constexpr const char* EXIT_POINT = "Exit\0";
+ static constexpr const char* FORMAT_FLASH_POINT = "Format flash\0";
+ // Login/password types
+ static constexpr const uint8_t* FORM = (const uint8_t*)"FORM\0";
+ static constexpr const uint8_t* CONSOLE = (const uint8_t*)"CONSOLE\0";
+ // Database states
+ static constexpr const char* SUCCESS = "Success!\0";
+ static constexpr const char* SIGNATURE_ERROR = "Signature error!\0";
+ static constexpr const char* MASTER_KEY_ERROR = "Master key error!\0";
+ static constexpr const char* CREDENTIALS_ERROR = "Credentials error!\0";
+ static constexpr const char* DB_FILE_ERROR = "Db file error!\0";
+ static constexpr const char* DATA_HASH_ERROR = "Data hash error!\0";
+ };
+
+ static constexpr size_t KEYS_BUFFER_SIZE = 128;
+ static size_t WRONG_PASSWORD_DELAY = 1000;
+
+ inline size_t abs(int32_t val) {
+ return (val < 0) ? -val : val;
+ }
+}
+
+class TildaLogic {
+public:
+ typedef UsbRawData DataT;
+ typedef DataT* DataPtr;
+ typedef const DataT* DataConstPtr;
+
+ typedef DataT* DataBuffer;
+ typedef const DataT* DataBufferConst;
+
+ constexpr static size_t MAX_MENU_POINTS_COUNT = 100;
+ using MenuT = Menu<MAX_MENU_POINTS_COUNT>;
+
+ constexpr static size_t MAX_TREE_NODES_COUNT = MenuT::COUNT_OF_POINTS;
+ using MenuTreeT = Tree<MAX_TREE_NODES_COUNT, MenuT::ContainerT>;
+
+ using CallbackT = MenuT::TreeT::TreeNodeT::CallbackT;
+ using CallbackArg = MenuT::TreeT::TreeNodeT::CallbackArg;
+
+ using KeyBuffer = etl::vector<AsciiCodeType, Private::KEYS_BUFFER_SIZE>;
+
+ enum class State {
+ PASSIVE_MODE,
+ MENU_MODE_START,
+ MENU_MODE,
+ MENU_MODE_END,
+ ENTER_MASTER_PASSWORD,
+ MASTER_PASSWORD_PASSED,
+ SEARCH_MODE
+ };
+
+ struct SpecialPoints {
+ MenuT::PointDescr<fd::FastDelegate0<>> formatFat;
+ };
+
+ struct FixedMenu {
+ MenuT::PointDescr<CallbackT> settings;
+ MenuT::PointDescr<CallbackT> exit;
+ };
+
+ static constexpr const char* KEEPASS_BASE_FILE = "db.kdb";
+ static constexpr UsbKey TILDA_MODE_KEY = UsbKey::KEY_GRAVE_ACCENT_AND_TILDE;
+
+ // Constructors
+ TildaLogic(UsbDequeStandart* deque, const SpecialPoints& specialPoints);
+ ~TildaLogic();
+
+ // Public methods
+ void process(DataBufferConst inputData, size_t length);
+
+private:
+ SpecialPoints _specialMenuPoints;
+ FixedMenu _fixedMenu;
+
+ friend class Private::FixedMenuCallbacks;
+ Private::FixedMenuCallbacks* _fixedMenuCbs;
+
+ State _currentState;
+
+ UsbKey _tildaKey;
+ UsbSpecialKeySequence _tildaSeq;
+
+ DataBufferConst _inputData;
+ size_t _inputDataLength;
+ UsbPackageConst* _inputPackagePtr;
+
+ MenuTreeT _menuTree;
+ MenuT _menu;
+
+ PackageFactory _packageFactory;
+
+ UsbPackage _lastPackage;
+ KeyBuffer _keysBuffer;
+ size_t _lastKeysBufferLen;
+ KeyboardLikeInput<KeyBuffer> _keyboardInput;
+
+ KeepAss::KeePassReader _keepassReader;
+ DB::XmlTree _db;
+ KeepAss::DecryptionResult _dbState;
+
+ TildaLogic(const TildaLogic&);
+
+ void _init();
+ void _buildTree(uint32_t index);
+ void _buildMenuTree();
+ void _buildMenu();
+ void _buildFixedMenu();
+ template<typename T> void _addMenuPoint(T& point);
+ void _copyDbContainer(uint32_t index);
+
+ void _dbDecrypt(const char* passwd, size_t len);
+
+ void _setState(State state) {
+ _currentState = state;
+ }
+
+ void _logInCallback(MenuT::ContainerT& container);
+
+ void _processMasterPassword();
+ void _processMenuMode();
+ const char* _getDbErrorType();
+
+ void _checkMode();
+ void _switchMenuMode();
+ void _sendMenuGreeting();
+
+ void _searchMode();
+
+ void _redirectInput();
+ void _sendMsg(const char* msg);
+ void _clearMsg(const char* msg);
+};
+
+namespace Private {
+ class FixedMenuCallbacks
+ {
+ public:
+ FixedMenuCallbacks(TildaLogic* logic);
+
+ void formatFat(TildaLogic::CallbackArg arg);
+ void exit(TildaLogic::CallbackArg arg);
+
+ private:
+ TildaLogic* _logic;
+ };
+}
+
+} // namespace Logic
+
+#endif /* TILDALOGIC_H_ */
diff --git a/emb/pastilda/menu/UsbPackageFactory.cpp b/emb/pastilda/menu/UsbPackageFactory.cpp
new file mode 100644
index 0000000..bf4a7aa
--- /dev/null
+++ b/emb/pastilda/menu/UsbPackageFactory.cpp
@@ -0,0 +1,252 @@
+/*
+ * This file is part of the pastilda project.
+ * hosted at http://github.com/thirdpin/pastilda
+ *
+ * Copyright (C) 2016 Third Pin LLC
+ *
+ * Written by:
+ * Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ * Dmitrii Lisin <mrlisdim@ya.ru>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <cstddef>
+#include <cstring>
+
+#include <keys/Key.h>
+
+#include <usb_deque.h>
+#include <UsbPackageFactory.h>
+
+using std::size_t;
+using namespace Keys;
+
+namespace UsbPackages {
+
+PackageFactory::PackageFactory() :
+ _packageDeque(new PackageDeque()),
+ _inputData(nullptr),
+ _inputDataLength(0),
+ _currentPackage(nullptr),
+ _currentPackageFieldNum(0),
+ _lastKey(UsbKey::NOT_A_KEY)
+{ }
+
+PackageFactory::PackageFactory(PackageDeque* deque) :
+ _packageDeque(deque),
+ _inputData(nullptr),
+ _inputDataLength(0),
+ _currentPackage(nullptr),
+ _currentPackageFieldNum(0),
+ _lastKey(UsbKey::NOT_A_KEY)
+{ }
+
+
+PackageFactory::~PackageFactory()
+{ }
+
+void PackageFactory::generatePackage(InputDataConst inputData)
+{
+ _packageDeque->unlock();
+ auto inputPackage = reinterpret_cast<UsbPackageConst*>(inputData);
+ _packageDeque->push_back(*inputPackage);
+ _packageDeque->lock();
+}
+
+void PackageFactory::generateClearSequence()
+{
+ _addEmptyPackage();
+ _addClearPackage();
+ _addEmptyPackage();
+}
+
+void PackageFactory::generateClearSequence(size_t count)
+{
+ Key backspaceKey(UsbKey::KEY_BACKSPACE);
+
+ _addEmptyPackage();
+ for (size_t i = 0; i < count; ++i) {
+ _addSimplePackage(backspaceKey);
+ }
+ _addEmptyPackage();
+}
+
+void PackageFactory::generateTabPackage()
+{
+ _addEmptyPackage();
+
+ Key tabKey(UsbKey::KEY_TAB);
+ _addSimplePackage(tabKey);
+
+ _addEmptyPackage();
+}
+
+void PackageFactory::generateEnterPackage()
+{
+ _addEmptyPackage();
+
+ Key enterKey(UsbKey::KEY_ENTER);
+ _addSimplePackage(enterKey);
+
+ _addEmptyPackage();
+}
+
+void PackageFactory::generateEmptyPackage()
+{
+ _addEmptyPackage();
+}
+
+void PackageFactory::_addClearPackage()
+{
+ Key aKey(UsbKey::KEY_A, UsbSpecialKey::LEFT_CTRL);
+ Key deleteKey(UsbKey::KEY_DELETE);
+
+ _addEmptyPackage();
+ _addSimplePackage(aKey);
+ _addEmptyPackage();
+ _addSimplePackage(deleteKey);
+ _addEmptyPackage();
+}
+
+void PackageFactory::processData(const basic_string_view<uint8_t>& inputData)
+{
+ _inputDataLength = inputData.length();
+ _inputData = reinterpret_cast<InputDataConst>(inputData.data());
+ _processInputData();
+}
+
+void PackageFactory::processData(InputDataConst inputData,
+ size_t inputDataLength)
+{
+ _inputDataLength = inputDataLength;
+ _inputData = inputData;
+ _processInputData();
+}
+
+void PackageFactory::processData(const char* inputData,
+ size_t inputDataLength)
+{
+ _inputDataLength = inputDataLength;
+ _inputData = reinterpret_cast<InputDataConst>(inputData);
+ _processInputData();
+}
+
+void PackageFactory::_processInputData()
+{
+ for (size_t iSymbol = 0; iSymbol < _inputDataLength; iSymbol++) {
+ Key key(_inputData[iSymbol]);
+
+ if (key.isShifted()) {
+ _addShiftedPackage(key);
+ }
+ else {
+ _addSimplePackage(key);
+ }
+ }
+ _addEmptyPackage();
+}
+
+inline void PackageFactory::_completeLastSimplePackage()
+{
+ bool lastPackageNotCompleted = (_currentPackageFieldNum > 0);
+ if (lastPackageNotCompleted) {
+ _currentPackageFieldNum = 0;
+ _packageDeque->lock();
+ }
+}
+
+void PackageFactory::_addEmptyPackage()
+{
+ _completeLastSimplePackage();
+
+ bool dequeWasLocked = _packageDeque->isLocked();
+ _packageDeque->unlock();
+ {
+ _packageDeque->push_back();
+
+ UsbPackage& currentPackage = _packageDeque->back();
+
+ currentPackage.clear();
+ }
+ if (dequeWasLocked) { // if deque was locked before adding empty package,
+ _packageDeque->lock(); // then lock it, otherwise it's something
+ } // need deque unlocked (e.g. simple package)
+}
+
+void PackageFactory::_addShiftedPackage(Key& key)
+{
+ _packageDeque->unlock();
+ {
+ _addEmptyPackage(); // clear last key
+ _addEmptyPackage(); // add new empty package
+
+ UsbPackage& currentPackage = _packageDeque->back();
+
+ currentPackage.special = key.getUsbKeyModifier();
+ currentPackage.key[0] = key.getUsbKey();
+ }
+ _packageDeque->lock();
+}
+
+void PackageFactory::_addSimplePackage(Key& key)
+{
+ // If in one package will be two same keys one
+ // by one, then the only one will be send. So we
+ // should split package if we have this situation.
+ if (_currentPackageFieldNum == 0 || key == _lastKey) {
+ _newSimplePackage(key);
+ }
+ else {
+ _continueSimplePackage(key);
+ }
+
+ _lastKey = key;
+ _checkSimplePackageEnd();
+}
+
+void PackageFactory::_continueSimplePackage(Key& key)
+{
+ _currentPackageFieldNum++;
+ size_t currentKeyNum =
+ _currentPackageFieldNum - USB_PACKAGE_SPECIAL_FIELDS_LENGTH;
+
+ UsbPackage& currentPackage = _packageDeque->back();
+ currentPackage.key[currentKeyNum] = key.getUsbKey();
+}
+
+void PackageFactory::_newSimplePackage(Key& key)
+{
+ _packageDeque->unlock();
+
+ _addEmptyPackage(); // clear last key
+ _addEmptyPackage(); // add new empty package
+
+ UsbPackage& currentPackage = _packageDeque->back();
+ currentPackage.special = key.getUsbKeyModifier();
+ currentPackage.reserved = _EMPTY_FIELD;
+ currentPackage.key[0] = key.getUsbKey();
+
+ _currentPackageFieldNum = 2; // last set field
+}
+
+void PackageFactory::_checkSimplePackageEnd()
+{
+ if (_currentPackageFieldNum == USB_PACKAGE_LENGTH - 6) { // USB_PACKAGE_LENGTH - 5 = 2,
+ _completeLastSimplePackage(); // what means, that there will be
+ } // only one key per package,
+ // otherwise linux don't work
+}
+
+} /* namespace UsbPackages */
diff --git a/emb/pastilda/menu/UsbPackageFactory.h b/emb/pastilda/menu/UsbPackageFactory.h
new file mode 100644
index 0000000..d8c0931
--- /dev/null
+++ b/emb/pastilda/menu/UsbPackageFactory.h
@@ -0,0 +1,90 @@
+/*
+ * This file is part of the pastilda project.
+ * hosted at http://github.com/thirdpin/pastilda
+ *
+ * Copyright (C) 2016 Third Pin LLC
+ *
+ * Written by:
+ * Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ * Dmitrii Lisin <mrlisdim@ya.ru>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PACKGES_PACKAGEFACTORY_H_
+#define PACKGES_PACKAGEFACTORY_H_
+
+#include <cstddef>
+#include <string>
+#include <experimental/string_view>
+
+#include <usb_deque.h>
+#include <keys/Key.h>
+
+using std::experimental::basic_string_view;
+using namespace Keys;
+using std::size_t;
+using std::string;
+
+namespace UsbPackages {
+
+class PackageFactory {
+public:
+ typedef const AsciiCodeType* InputDataConst;
+ typedef UsbRawData* OutputData;
+ using PackageDeque = UsbDequeStandart;
+
+ PackageFactory();
+ PackageFactory(PackageDeque* deque);
+ ~PackageFactory();
+
+ void processData(InputDataConst inputData, size_t inputDataLength);
+ void processData(const basic_string_view<uint8_t>& inputData);
+ void processData(const char* inputData, size_t inputDataLength);
+ void generateClearSequence();
+ void generateClearSequence(size_t count);
+ void generateEmptyPackage();
+ void generateTabPackage();
+ void generateEnterPackage();
+ void generatePackage(InputDataConst inputData);
+
+private:
+ constexpr static UsbRawData _EMPTY_FIELD = 0;
+
+ PackageDeque* _packageDeque;
+
+ InputDataConst _inputData;
+ size_t _inputDataLength;
+
+ UsbPackage* _currentPackage;
+ size_t _currentPackageFieldNum;
+
+ Key _lastKey;
+
+ void _processInputData();
+
+ void _addEmptyPackage();
+ void _addClearPackage();
+ void _addShiftedPackage(Key& key);
+
+ void _addSimplePackage(Key& key);
+ void _continueSimplePackage(Key& key);
+ void _newSimplePackage(Key& key);
+ void _checkSimplePackageEnd();
+ void _completeLastSimplePackage();
+};
+
+} /* namespace UsbPackages */
+
+#endif /* PACKGES_PACKAGEFACTORY_H_ */
diff --git a/emb/pastilda/tree/Tree.hpp b/emb/pastilda/tree/Tree.hpp
new file mode 100644
index 0000000..10009af
--- /dev/null
+++ b/emb/pastilda/tree/Tree.hpp
@@ -0,0 +1,272 @@
+/*
+ * This file is part of the pastilda project.
+ * hosted at http://github.com/thirdpin/pastilda
+ *
+ * Copyright (C) 2016 Third Pin LLC
+ *
+ * Written by:
+ * Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ * Dmitrii Lisin <mrlisdim@ya.ru>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef TREE_H_
+#define TREE_H_
+
+#include <string>
+#include <functional>
+
+#include <etl/pool.h>
+
+#include <TreeNode.hpp>
+
+template <std::size_t size, typename T>
+class Tree {
+public:
+ static constexpr std::size_t NODES_COUNT = size;
+
+ using TreeNodeT = TreeNode<T>;
+ using TreeNodePtr = TreeNode<T>*;
+
+ using ContainerT = typename TreeNodeT::Container;
+ using CallbackT = typename TreeNodeT::CallbackT;
+ using CallbackArg = typename TreeNodeT::CallbackArg;
+
+ using PoolType = etl::pool<TreeNodeT, NODES_COUNT>;
+ using PoolPtr = PoolType*;
+
+ Tree();
+ Tree(TreeNodePtr node, PoolPtr pool);
+ virtual ~Tree();
+
+ size_t getCurrentChildNum();
+
+ void addChild(const CallbackT callback,
+ const CallbackArg container);
+ void addChild(const CallbackT callback = &TreeNodeT::EMPTY_CALLBACK);
+ void addNeighbor(const CallbackT callback,
+ const CallbackArg container);
+ void addNeighbor(const CallbackT callback = &TreeNodeT::EMPTY_CALLBACK);
+
+ void moveLeft();
+ void moveRight();
+ void moveInto();
+ void moveOut();
+
+ void moveInHead();
+ void moveMostRight();
+ void moveMostLeft();
+
+ bool isMostLeft() {
+ return (_currentNode->getLeftNeighbor() == nullptr);
+ }
+
+ bool isMostRight() {
+ return (_currentNode->getRightNeighbor() == nullptr);
+ }
+
+ bool isMostTop() {
+ return (_currentNode->getParent() == nullptr);
+ }
+
+ bool isMostBottom() {
+ return (_currentNode->isEndNode());
+ }
+
+ TreeNodePtr getCurrentNode() {
+ return _currentNode;
+ }
+
+ bool isFull() {
+ return _pool->full();
+ }
+
+ void destroy();
+
+private:
+ PoolPtr _pool;
+ TreeNodePtr _currentNode;
+
+ void _destroyNode(TreeNodePtr node);
+ void _destroyTree(TreeNodePtr tree);
+};
+
+template <std::size_t size, typename T>
+Tree<size, T>::Tree() :
+ _pool(new PoolType()),
+ _currentNode(_pool->allocate())
+{ }
+
+template <std::size_t size, typename T>
+Tree<size, T>::Tree(TreeNodePtr node, PoolPtr pool) :
+ _pool(pool),
+ _currentNode(node)
+{ }
+
+template <std::size_t size, typename T>
+Tree<size, T>::~Tree()
+{ }
+
+template<std::size_t size, typename T>
+size_t Tree<size, T>::getCurrentChildNum()
+{
+ TreeNodePtr node = _currentNode;
+ size_t childNum = node->getParent()->getChildrenCount();
+
+ while (node != nullptr) {
+ childNum--;
+ node = node->getLeftNeighbor();
+ }
+
+ childNum = _currentNode->getParent()->getChildrenCount() - childNum - 1;
+
+ return childNum;
+}
+
+template<std::size_t size, typename T>
+void Tree<size, T>::addChild(const CallbackT callback,
+ const CallbackArg container)
+{
+ if (this->isFull() == false) {
+ TreeNodePtr child = _pool->allocate();
+ child->setCallback(callback);
+ child->setContainer(container);
+
+ _currentNode->addChild(child);
+ }
+}
+
+template<std::size_t size, typename T>
+void Tree<size, T>::addChild(const CallbackT callback)
+{
+ if (this->isFull() == false) {
+ TreeNodePtr child = _pool->allocate();
+ child->setCallback(callback);
+
+ _currentNode->addChild(child);
+ }
+}
+
+template<std::size_t size, typename T>
+void Tree<size, T>::addNeighbor(const CallbackT callback,
+ const CallbackArg container)
+{
+ if (this->isFull() == false) {
+ TreeNodePtr neighbor = _pool->allocate();
+ neighbor->setCallback(callback);
+ neighbor->setContainer(container);
+
+ _currentNode->addRightNeighbor(neighbor);
+ }
+}
+
+template<std::size_t size, typename T>
+void Tree<size, T>::addNeighbor(const CallbackT callback)
+{
+ if (this->isFull() == false) {
+ TreeNodePtr neighbor = _pool->allocate();
+ neighbor->setCallback(callback);
+
+ _currentNode->addRightNeighbor(neighbor);
+ }
+}
+
+
+template<std::size_t size, typename T>
+void Tree<size, T>::moveLeft()
+{
+ if (this->isMostLeft() == false) {
+ _currentNode = _currentNode->getLeftNeighbor();
+ }
+}
+
+template<std::size_t size, typename T>
+void Tree<size, T>::moveRight()
+{
+ if (this->isMostRight() == false) {
+ _currentNode = _currentNode->getRightNeighbor();
+ }
+}
+
+template<std::size_t size, typename T>
+void Tree<size, T>::moveInto()
+{
+ if (_currentNode->isEndNode() == false) {
+ _currentNode = _currentNode->getChildAt(0);
+ }
+}
+
+template<std::size_t size, typename T>
+void Tree<size, T>::moveOut()
+{
+ if (this->isMostTop() == false) {
+ _currentNode = _currentNode->getParent();
+ }
+}
+
+template<std::size_t size, typename T>
+void Tree<size, T>::destroy()
+{
+ _pool->release_all();
+ _currentNode = _pool->allocate();
+}
+
+template<std::size_t size, typename T>
+void Tree<size, T>::moveInHead()
+{
+ while (isMostTop() == false) {
+ moveOut();
+ }
+}
+
+template<std::size_t size, typename T>
+void Tree<size, T>::moveMostRight()
+{
+ while (isMostRight() == false) {
+ moveRight();
+ }
+}
+
+template<std::size_t size, typename T>
+void Tree<size, T>::moveMostLeft()
+{
+ while (isMostLeft() == false) {
+ moveLeft();
+ }
+}
+
+template<std::size_t size, typename T>
+void Tree<size, T>::_destroyTree(TreeNodePtr tree)
+{
+ const std::size_t CHILDREN_COUNT = tree->getChildrenCount();
+ for (std::size_t i = 0; i < CHILDREN_COUNT; ++i) {
+ TreeNodePtr child = tree->getChildAt(CHILDREN_COUNT - i - 1);
+ if (child->isEndNode()) {
+ _destroyNode(child);
+ }
+ else {
+ _destroyTree(child);
+ }
+ }
+ _destroyNode(tree);
+}
+
+template<std::size_t size, typename T>
+void Tree<size, T>::_destroyNode(TreeNodePtr node)
+{
+ destroyTreeNode(node);
+}
+
+#endif /* TREE_H_ */
diff --git a/emb/pastilda/tree/TreeNode.hpp b/emb/pastilda/tree/TreeNode.hpp
new file mode 100644
index 0000000..860dc4b
--- /dev/null
+++ b/emb/pastilda/tree/TreeNode.hpp
@@ -0,0 +1,225 @@
+/*
+ * This file is part of the pastilda project.
+ * hosted at http://github.com/thirdpin/pastilda
+ *
+ * Copyright (C) 2016 Third Pin LLC
+ *
+ * Written by:
+ * Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ * Dmitrii Lisin <mrlisdim@ya.ru>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef TREE_TREENODE_HPP_
+#define TREE_TREENODE_HPP_
+
+#include <string>
+#include <functional>
+
+#include <etl/vector.h>
+#include <FastDelegate.h>
+
+constexpr size_t MAX_CHILDREN_COUNT = 5;
+
+namespace fd = fastdelegate;
+
+template<typename T>
+class TreeNode {
+public:
+ using TreeNodePtr = TreeNode*;
+ using Container = T;
+
+ using CallbackArg = Container&;
+ using CallbackT = fd::FastDelegate1<CallbackArg>;
+
+ static void EMPTY_CALLBACK(CallbackArg) {
+ return;
+ }
+
+ TreeNode();
+ TreeNode(std::string name, TreeNodePtr parent);
+ ~TreeNode();
+
+ void setContainer(const Container& container) {
+ _container = container;
+ }
+
+ void setCallback(const CallbackT& callback) {
+ _callback = callback;
+ }
+
+ void call() {
+ _callback(_container);
+ }
+
+ Container& getContainer() {
+ return _container;
+ }
+
+ void setParent(TreeNodePtr parent) {
+ _parent = parent;
+ }
+
+ TreeNodePtr getParent() {
+ return _parent;
+ }
+
+ void addChild(TreeNodePtr child);
+ TreeNodePtr getChildAt(const std::size_t i) const;
+
+ std::size_t getChildrenCount() {
+ return _childrenCount;
+ }
+
+ bool isEndNode() const {
+ return (_children == nullptr);
+ }
+
+ void addLeftNeighbor(TreeNodePtr neighbor);
+ void addRightNeighbor(TreeNodePtr neighbor);
+
+ TreeNodePtr getLeftNeighbor() const {
+ return _leftNeighbor;
+ }
+
+ TreeNodePtr getRightNeighbor() const {
+ return _rightNeighbor;
+ }
+
+ friend void destroyTreeNode(TreeNode* node)
+ {
+ node->setParent(nullptr);
+ node->_setRightNeighbor(nullptr);
+ node->_setLeftNeighbor(nullptr);
+ node->_children = nullptr;
+ node->_childrenCount = 0;
+ }
+
+protected:
+ Container _container;
+ CallbackT _callback;
+
+ TreeNodePtr _parent;
+ std::size_t _childrenCount;
+ TreeNodePtr _children;
+ TreeNodePtr _leftNeighbor;
+ TreeNodePtr _rightNeighbor;
+
+ void _addFirstChild(TreeNodePtr child);
+ void _setLeftNeighbor(TreeNodePtr neighbor);
+ void _setRightNeighbor(TreeNodePtr neighbor);
+};
+
+template<typename T>
+TreeNode<T>::TreeNode():
+ _callback(EMPTY_CALLBACK),
+ _parent(nullptr),
+ _childrenCount(0),
+ _children(nullptr),
+ _leftNeighbor(nullptr),
+ _rightNeighbor(nullptr)
+{ }
+
+template<typename T>
+TreeNode<T>::TreeNode(std::string name, TreeNodePtr parent):
+ _callback(EMPTY_CALLBACK),
+ _parent(parent),
+ _childrenCount(0),
+ _children(nullptr),
+ _leftNeighbor(nullptr),
+ _rightNeighbor(nullptr)
+{ }
+
+template<typename T>
+TreeNode<T>::~TreeNode()
+{
+ destroyTreeNode(this);
+}
+
+template<typename T>
+inline void TreeNode<T>::_addFirstChild(TreeNodePtr child)
+{
+ _children = child;
+}
+
+template<typename T>
+void TreeNode<T>::addChild(TreeNodePtr child)
+{
+ _childrenCount++;
+
+ child->setParent(this);
+
+ if (_childrenCount == 1) {
+ _addFirstChild(child);
+ }
+ else {
+ _children->addRightNeighbor(child);
+ }
+}
+
+template<typename T>
+void TreeNode<T>::addLeftNeighbor(TreeNodePtr neighbor)
+{
+ if (_leftNeighbor == nullptr) {
+ _leftNeighbor = neighbor;
+ neighbor->_setRightNeighbor(this);
+ }
+ else {
+ _leftNeighbor->addLeftNeighbor(neighbor);
+ }
+}
+
+template<typename T>
+void TreeNode<T>::addRightNeighbor(TreeNodePtr neighbor)
+{
+ if (_rightNeighbor == nullptr) {
+ _rightNeighbor = neighbor;
+ neighbor->_setLeftNeighbor(this);
+ }
+ else {
+ _rightNeighbor->addRightNeighbor(neighbor);
+ }
+}
+
+template<typename T>
+inline void TreeNode<T>::_setLeftNeighbor(TreeNodePtr neighbor)
+{
+ _leftNeighbor = neighbor;
+}
+
+template<typename T>
+inline void TreeNode<T>::_setRightNeighbor(TreeNodePtr neighbor)
+{
+ _rightNeighbor = neighbor;
+}
+
+template<typename T>
+typename TreeNode<T>::TreeNodePtr TreeNode<T>::getChildAt(const std::size_t childNum) const
+{
+ if (this->isEndNode()) {
+ return nullptr;
+ }
+
+ std::size_t i = 0;
+ TreeNodePtr child = _children;
+ while (i < childNum) {
+ child = child->getRightNeighbor();
+ ++i;
+ }
+
+ return child;
+}
+
+#endif /* TREE_TREENODE_HPP_ */
diff --git a/emb/pastilda/usb/usb_device/usb_deque.h b/emb/pastilda/usb/usb_device/usb_deque.h
new file mode 100644
index 0000000..a128837
--- /dev/null
+++ b/emb/pastilda/usb/usb_device/usb_deque.h
@@ -0,0 +1,86 @@
+/*
+ * This file is part of the pastilda project.
+ * hosted at http://github.com/thirdpin/pastilda
+ *
+ * Copyright (C) 2016 Third Pin LLC
+ *
+ * Written by:
+ * Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ * Dmitrii Lisin <mrlisdim@ya.ru>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef USB_USB_DEVICE_USB_DEQUE_H_
+#define USB_USB_DEVICE_USB_DEQUE_H_
+
+#include <cstring>
+#include <cstddef>
+
+#include <etl/deque.h>
+
+#include <keys/Key.h>
+#include <usb_package.h>
+
+using namespace Keys;
+using std::size_t;
+using std::memcmp;
+
+namespace UsbPackages {
+
+template <size_t USB_PACKAGE_DEQUE_SIZE>
+class UsbDeque
+{
+public:
+ using impl = etl::deque<UsbPackage, USB_PACKAGE_DEQUE_SIZE>;
+};
+
+
+template <size_t USB_PACKAGE_DEQUE_SIZE>
+class UsbDequeSave : public UsbDeque<USB_PACKAGE_DEQUE_SIZE>::impl
+{
+public:
+ UsbDequeSave() :
+ UsbDeque<USB_PACKAGE_DEQUE_SIZE>::impl(),
+ dequeLocked(true)
+ { }
+
+ void lock() {
+ dequeLocked = true;
+ }
+
+ void unlock() {
+ dequeLocked = false;
+ }
+
+ bool isPopOnly() {
+ return isLocked();
+ }
+
+ bool isLocked() {
+ return dequeLocked;
+ }
+
+private:
+ bool dequeLocked;
+};
+
+
+static constexpr size_t USB_DEQUE_STANDART_SIZE = 500;
+using UsbDequeStandart = UsbDequeSave<USB_DEQUE_STANDART_SIZE>;
+
+} /* namespace UsbPackages */
+
+
+#endif /* USB_USB_DEVICE_USB_DEQUE_H_ */
diff --git a/emb/pastilda/usb/usb_device/usb_package.h b/emb/pastilda/usb/usb_device/usb_package.h
new file mode 100644
index 0000000..a0b39e9
--- /dev/null
+++ b/emb/pastilda/usb/usb_device/usb_package.h
@@ -0,0 +1,88 @@
+/*
+ * This file is part of the pastilda project.
+ * hosted at http://github.com/thirdpin/pastilda
+ *
+ * Copyright (C) 2016 Third Pin LLC
+ *
+ * Written by:
+ * Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ * Dmitrii Lisin <mrlisdim@ya.ru>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef USB_USB_DEVICE_USB_PACKAGE_H_
+#define USB_USB_DEVICE_USB_PACKAGE_H_
+
+#include <cstddef>
+#include <cstring>
+
+#include <keys/Key.h>
+
+using namespace Keys;
+using std::size_t;
+using std::memset;
+
+namespace UsbPackages {
+
+typedef uint8_t UsbRawData;
+
+constexpr static UsbRawData USB_EMPTY_FIELD = 0;
+
+constexpr static size_t USB_PACKAGE_LENGTH = 8;
+constexpr static size_t USB_PACKAGE_SPECIAL_FIELDS_LENGTH = 2;
+constexpr static size_t USB_PACKAGE_KEY_FIELDS_LENGTH = 6;
+
+#pragma pack(push, 1)
+struct UsbPackage
+{
+ UsbSpecialKeySequence special;
+ UsbRawData reserved;
+ UsbKey key[USB_PACKAGE_KEY_FIELDS_LENGTH];
+
+ friend bool operator==(const UsbPackage& lhs, const UsbPackage& rhs) {
+ return (memcmp(&lhs, &rhs, UsbPackages::USB_PACKAGE_LENGTH) == 0);
+ }
+
+ friend bool operator!=(const UsbPackage& lhs, const UsbPackage& rhs) {
+ return !(memcmp(&lhs, &rhs, UsbPackages::USB_PACKAGE_LENGTH) == 0);
+ }
+
+ UsbRawData* data() {
+ return reinterpret_cast<UsbRawData*>(this);
+ }
+
+ const UsbRawData* data() const {
+ return reinterpret_cast<const UsbRawData*>(this);
+ }
+
+ constexpr size_t length() const {
+ return USB_PACKAGE_LENGTH;
+ }
+
+ void clear() {
+ memset(data(), USB_EMPTY_FIELD, length());
+ }
+};
+#pragma pack(pop)
+
+using UsbPackageConst = const UsbPackage;
+
+static UsbPackageConst ZERO_PACKAGE = {{USB_EMPTY_FIELD}, USB_EMPTY_FIELD,
+ UsbKey::NOT_A_KEY, UsbKey::NOT_A_KEY, UsbKey::NOT_A_KEY,
+ UsbKey::NOT_A_KEY, UsbKey::NOT_A_KEY, UsbKey::NOT_A_KEY};
+
+} // namespace UsbPackage
+
+#endif /* USB_USB_DEVICE_USB_PACKAGE_H_ */
diff --git a/emb/pastilda/usb/usb_device/usbd_composite.cpp b/emb/pastilda/usb/usb_device/usbd_composite.cpp
index 6136594..bce295b 100644
--- a/emb/pastilda/usb/usb_device/usbd_composite.cpp
+++ b/emb/pastilda/usb/usb_device/usbd_composite.cpp
@@ -3,7 +3,10 @@
* hosted at http://github.com/thirdpin/pastilda
*
* Copyright (C) 2016 Third Pin LLC
- * Written by Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ *
+ * Written by:
+ * Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ * Dmitrii Lisin <mrlisdim@ya.ru>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,14 +22,45 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <usb/usb_device/usbd_composite.h>
+#include "menu/UsbPackageFactory.h"
+#include "keys/Key.h"
+#include "stdio.h"
+
+#include "usbd_composite.h"
using namespace GPIO_CPP_Extension;
USB_composite *usb_pointer;
-USB_composite::USB_composite(const uint32_t block_count,
- int (*read_block)(uint32_t lba, uint8_t *copy_to),
- int (*write_block)(uint32_t lba, const uint8_t *copy_from))
+
+void USB_composite::device_keybord_interrupt(usbd_device*, unsigned char)
+{
+ static UsbPackage lastPackage = UsbPackages::ZERO_PACKAGE;
+
+ UsbDequeStandart* usbDeque = usb_pointer->get_usb_deque();
+
+ if (usbDeque->isPopOnly() && !usbDeque->empty()) {
+ UsbPackage& package = usbDeque->front();
+
+ lastPackage = package;
+
+ size_t result = usb_pointer->usb_send_packet_nonblock(
+ package.data(), package.length()
+ );
+
+ bool packageSended = (result != 0);
+ if (packageSended) {
+ usbDeque->pop_front();
+ }
+ }
+ else {
+ usb_pointer->usb_send_packet_nonblock(
+ lastPackage.data(), lastPackage.length()
+ );
+ }
+}
+
+
+USB_composite::USB_composite(UsbMemoryControlParams memoryParams)
{
usb_pointer = this;
descriptors = new UsbCompositeDescriptors();
@@ -40,15 +74,32 @@ USB_composite::USB_composite(const uint32_t block_count,
uf_p.set_af(AF_Number::AF10);
uf_m.set_af(AF_Number::AF10);
- my_usb_device = usbd_init(&otgfs_usb_driver, &(UsbCompositeDescriptors::dev),
- &(UsbCompositeDescriptors::config_descr), (const char**)UsbCompositeDescriptors::usb_strings, 3,
- usbd_control_buffer, sizeof(usbd_control_buffer));
+ my_usb_device = usbd_init(&otgfs_usb_driver, &(descriptors->dev),
+ &(descriptors->config_descr), (const char**)descriptors->usb_strings, 3,
+ usbd_control_buffer, sizeof(usbd_control_buffer));
usbd_register_set_config_callback(my_usb_device, USB_set_config_callback);
+
+ usb_msc_init(my_usb_device,
+ Endpoint::E_MASS_STORAGE_IN, 64, Endpoint::E_MASS_STORAGE_OUT, 64,
+ "ThirdPin", "Pastilda", "0.00",
+ memoryParams.block_count, memoryParams.read_block_func, memoryParams.write_block_func);
+
+ nvic_set_priority(NVIC_OTG_FS_IRQ, 0x01<<7);
nvic_enable_irq(NVIC_OTG_FS_IRQ);
+}
+
+void USB_composite::init_hid_interrupt()
+{
+ send_zero_package();
+}
- usb_msc_init(my_usb_device, Endpoint::E_MASS_STORAGE_IN, 64, Endpoint::E_MASS_STORAGE_OUT, 64,
- "ThirdPin", "Pastilda", "0.00", block_count, read_block, write_block);
+void USB_composite::send_zero_package()
+{
+ usb_send_packet_nonblock(
+ UsbPackages::ZERO_PACKAGE.data(),
+ UsbPackages::ZERO_PACKAGE.length()
+ );
}
void USB_composite::usb_send_packet(const void *buf, int len)
@@ -56,18 +107,15 @@ void USB_composite::usb_send_packet(const void *buf, int len)
while(usbd_ep_write_packet(my_usb_device, 0x81, buf, len) == 0);
}
-void USB_OTG_IRQ()
+uint16_t USB_composite::usb_send_packet_nonblock(const void *buf, int len)
{
- usbd_poll(usb_pointer->my_usb_device);
+ return usbd_ep_write_packet(my_usb_device, 0x81, buf, len);
}
-void USB_composite::hid_set_config(usbd_device *usbd_dev, uint16_t wValue)
+void USB_OTG_IRQ()
{
- (void)wValue;
- (void)usbd_dev;
-
- usbd_ep_setup(usbd_dev, Endpoint::E_KEYBOARD, USB_ENDPOINT_ATTR_INTERRUPT, 8, 0);
- usbd_register_control_callback(usbd_dev, USB_REQ_TYPE_INTERFACE, USB_REQ_TYPE_RECIPIENT, USB_control_callback );
+ usbd_poll(usb_pointer->my_usb_device);
+ usb_pointer->last_usb_request_time = get_counter_ms();
}
int USB_composite::hid_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len,
@@ -101,8 +149,9 @@ int USB_composite::hid_control_request(usbd_device *usbd_dev, struct usb_setup_d
{
if (req->bRequest == HidRequest::GET_REPORT)
{
- *buf = (uint8_t*)&boot_key_report;
- *len = sizeof(boot_key_report);
+ static UsbPackage package = UsbPackages::ZERO_PACKAGE;
+ *buf = package.data();
+ *len = package.length();
return (USBD_REQ_HANDLED);
}
else if (req->bRequest == HidRequest::GET_IDLE)
@@ -154,7 +203,7 @@ int USB_control_callback(usbd_device *usbd_dev,
struct usb_setup_data *req, uint8_t **buf, uint16_t *len,
usbd_control_complete_callback *complete)
{
- return(usb_pointer->hid_control_request(usbd_dev, req, buf, len, complete));
+ return( usb_pointer->hid_control_request(usbd_dev, req, buf, len, complete));
}
diff --git a/emb/pastilda/usb/usb_device/usbd_composite.h b/emb/pastilda/usb/usb_device/usbd_composite.h
index ac83f3b..883f08e 100644
--- a/emb/pastilda/usb/usb_device/usbd_composite.h
+++ b/emb/pastilda/usb/usb_device/usbd_composite.h
@@ -3,7 +3,10 @@
* hosted at http://github.com/thirdpin/pastilda
*
* Copyright (C) 2016 Third Pin LLC
- * Written by Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ *
+ * Written by:
+ * Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ * Dmitrii Lisin <mrlisdim@ya.ru>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,12 +22,16 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef USB_COMPOSITE_H
-#define USB_COMPOSITE_H
+#ifndef USB_MSC_H
+#define USB_MSC_H
+#include <fs/file_system.h>
#include "usbd_composite_desc.h"
#include "systick_ext.h"
#include "gpio_ext.h"
+#include "usb_deque.h"
+
+using namespace UsbPackages;
#define USB_OTG_IRQ otg_fs_isr
extern "C" void USB_OTG_IRQ();
@@ -38,29 +45,47 @@ static uint8_t keyboard_protocol = 1;
static uint8_t keyboard_idle = 0;
static uint8_t keyboard_leds = 0;
-static struct {
- uint8_t modifiers;
- uint8_t reserved;
- uint8_t keys[6];
-} boot_key_report;
-
class USB_composite
{
public:
uint8_t usbd_control_buffer[500];
UsbCompositeDescriptors *descriptors;
- uint8_t usb_ready = 0;
+ volatile uint32_t last_usb_request_time;
+
usbd_device *my_usb_device;
- USB_composite(const uint32_t block_count,
- int (*read_block)(uint32_t lba, uint8_t *copy_to),
- int (*write_block)(uint32_t lba, const uint8_t *copy_from));
+ USB_composite(UsbMemoryControlParams params);
void usb_send_packet(const void *buf, int len);
+ uint16_t usb_send_packet_nonblock(const void *buf, int len);
+
+ static void device_keybord_interrupt(usbd_device*, unsigned char);
+
+ void poll() {
+ usbd_poll(my_usb_device);
+ last_usb_request_time = get_counter_ms();
+ }
int hid_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len,
- void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req));
+ void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req));
+
+ void hid_set_config(usbd_device *usbd_dev, uint16_t wValue)
+ {
+ (void)wValue;
+ (void)usbd_dev;
+
+ usbd_ep_setup(usbd_dev, Endpoint::E_KEYBOARD, USB_ENDPOINT_ATTR_INTERRUPT, 8, device_keybord_interrupt);
+ usbd_register_control_callback(usbd_dev, USB_REQ_TYPE_INTERFACE, USB_REQ_TYPE_RECIPIENT, USB_control_callback );
+ }
+
+ UsbDequeStandart* get_usb_deque() {
+ return &_usbDeque;
+ }
+
+ void init_hid_interrupt();
+ void send_zero_package();
- void hid_set_config(usbd_device *usbd_dev, uint16_t wValue);
+private:
+ UsbDequeStandart _usbDeque;
};
#endif
diff --git a/emb/pastilda/usb/usb_device/usbd_composite_desc.cpp b/emb/pastilda/usb/usb_device/usbd_composite_desc.cpp
index c1018cc..9c4350e 100644
--- a/emb/pastilda/usb/usb_device/usbd_composite_desc.cpp
+++ b/emb/pastilda/usb/usb_device/usbd_composite_desc.cpp
@@ -3,7 +3,10 @@
* hosted at http://github.com/thirdpin/pastilda
*
* Copyright (C) 2016 Third Pin LLC
- * Written by Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ *
+ * Written by:
+ * Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ * Dmitrii Lisin <mrlisdim@ya.ru>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,7 +22,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <usb/usb_device/usbd_composite_desc.h>
+#include "usbd_composite_desc.h"
constexpr uint8_t UsbCompositeDescriptors::keyboard_report_descriptor[];
constexpr UsbCompositeDescriptors::type_hid_function UsbCompositeDescriptors::keyboard_hid_function;
diff --git a/emb/pastilda/usb/usb_device/usbd_composite_desc.h b/emb/pastilda/usb/usb_device/usbd_composite_desc.h
index 2c09aa0..b4d0181 100644
--- a/emb/pastilda/usb/usb_device/usbd_composite_desc.h
+++ b/emb/pastilda/usb/usb_device/usbd_composite_desc.h
@@ -3,7 +3,10 @@
* hosted at http://github.com/thirdpin/pastilda
*
* Copyright (C) 2016 Third Pin LLC
- * Written by Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ *
+ * Written by:
+ * Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ * Dmitrii Lisin <mrlisdim@ya.ru>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -36,8 +39,8 @@ typedef enum {
typedef enum : uint8_t {
E_KEYBOARD = 0x81,
- E_MASS_STORAGE_IN = 0x83,
- E_MASS_STORAGE_OUT = 0x03
+ E_MASS_STORAGE_IN = 0x83,
+ E_MASS_STORAGE_OUT = 0x03
} Endpoint;
typedef enum {
@@ -63,27 +66,20 @@ public:
static constexpr char usb_strings[][30] =
{
- "Third Pin",
+ "Third pin",
"Composite Device",
"Pastilda"
};
static constexpr struct usb_device_descriptor dev =
{
- USB_DT_DEVICE_SIZE, //bLength
- USB_DT_DEVICE, //bDescriptorType
- 0x0110, //bcdUSB
- 0x0, //bDeviceClass
- 0x00, //bDeviceSubClass
- 0x00, //bDeviceProtocol
- 64, //bMaxPacketSize0
- 0x0483, //idVendor
- 0x5741, //idProduct
- 0x0200, //bcdDevice
- 1, //iManufacturer
- 2, //iProduct
- 3, //iSerialNumber
- 1 //bNumConfigurations
+ USB_DT_DEVICE_SIZE,
+ USB_DT_DEVICE,
+ 0x0110,
+ 0x0,
+ 0x00, 0x00, 64,
+ 0x0483, 0x5741, 0x0200,
+ 1, 2, 3, 1
};
typedef struct __attribute__((packed))
@@ -98,109 +94,91 @@ public:
static constexpr type_hid_function keyboard_hid_function =
{
- {
- 9, //bLength
- USB_DT_HID, //bDescriptorType
- 0x0111, //bcdHID
- 0, //bCountryCode
- 1 //bNumDescriptors
- },
-
- {
- USB_DT_REPORT,
- sizeof(keyboard_report_descriptor)
- }
+ {
+ 9,
+ USB_DT_HID,
+ 0x0111, 0, 1
+ },
+
+ {
+ USB_DT_REPORT,
+ sizeof(keyboard_report_descriptor)
+ }
};
static constexpr struct usb_endpoint_descriptor hid_endpoint =
{
- USB_DT_ENDPOINT_SIZE, //bLength
- USB_DT_ENDPOINT, //bDescriptorType
- Endpoint::E_KEYBOARD, //bEndpointAddress
- USB_ENDPOINT_ATTR_INTERRUPT, //bmAttributes
- 64, //wMaxPacketSize
- 0x20 //bInterval
+ USB_DT_ENDPOINT_SIZE,
+ USB_DT_ENDPOINT, Endpoint::E_KEYBOARD,
+ USB_ENDPOINT_ATTR_INTERRUPT,
+ 64, 0x10
};
static constexpr struct usb_endpoint_descriptor msc_endpoint[] =
{
- {
- USB_DT_ENDPOINT_SIZE, //bLength
- USB_DT_ENDPOINT, //bDescriptorType
- Endpoint::E_MASS_STORAGE_IN, //bEndpointAddress
- USB_ENDPOINT_ATTR_BULK, //bmAttributes
- 64, //wMaxPacketSize
- 0 //bInterval
- },
-
- {
- USB_DT_ENDPOINT_SIZE, //bLength
- USB_DT_ENDPOINT, //bDescriptorType
- Endpoint::E_MASS_STORAGE_OUT, //bEndpointAddress
- USB_ENDPOINT_ATTR_BULK, //bmAttributes
- 64, //wMaxPacketSize
- 0 //bInterval
- }
+ {
+ USB_DT_ENDPOINT_SIZE,
+ USB_DT_ENDPOINT,
+ Endpoint::E_MASS_STORAGE_IN, USB_ENDPOINT_ATTR_BULK,
+ 64, 0
+ },
+
+ {
+ USB_DT_ENDPOINT_SIZE,
+ USB_DT_ENDPOINT,
+ Endpoint::E_MASS_STORAGE_OUT, USB_ENDPOINT_ATTR_BULK,
+ 64, 0
+ }
};
static constexpr struct usb_interface_descriptor iface[] =
{
- {
- USB_DT_INTERFACE_SIZE, //bLength
- USB_DT_INTERFACE, //bDescriptorType
- Interface::I_KEYBOARD, //bInterfaceNumber
- 0, //bAlternateSetting
- 1, //bNumEndpoints
- USB_CLASS_HID, //bInterfaceClass
- 1, //bInterfaceSubClass
- 1, //bInterfaceProtocol
- 0, //iInterface
- &hid_endpoint, &keyboard_hid_function,
- sizeof(keyboard_hid_function)
- },
+ {
+ USB_DT_INTERFACE_SIZE,
+ USB_DT_INTERFACE,
+ Interface::I_KEYBOARD, 0, 1,
+ USB_CLASS_HID,
+ 1, 1, 0,
+ &hid_endpoint, &keyboard_hid_function,
+ sizeof(keyboard_hid_function)
+ },
+
+ {
+ USB_DT_INTERFACE_SIZE,
+ USB_DT_INTERFACE,
+ Interface::I_MASS_STORAGE, 0, 2,
+ USB_CLASS_MSC,
+ USB_MSC_SUBCLASS_SCSI, USB_MSC_PROTOCOL_BBB, 0x00,
+ msc_endpoint, 0, 0
+ },
- {
- USB_DT_INTERFACE_SIZE, //bLength
- USB_DT_INTERFACE, //bDescriptorType
- Interface::I_MASS_STORAGE, //bInterfaceNumber
- 0, //bAlternateSetting
- 2, //bNumEndpoints
- USB_CLASS_MSC, //bInterfaceClass
- USB_MSC_SUBCLASS_SCSI, //bInterfaceSubClass
- USB_MSC_PROTOCOL_BBB, //bInterfaceProtocol
- 0x00, //iInterface
- msc_endpoint, 0, 0
- },
};
-
+ //array
static constexpr struct usb_config_descriptor::usb_interface ifaces[]
- {
- {
- (uint8_t *)0, //cur_altsetting
- 1, //num_altsetting
- (usb_iface_assoc_descriptor*)0, //iface_assoc
- &iface[Interface::I_KEYBOARD] //altsetting
- },
-
- {
- (uint8_t *)0, //cur_altsetting
- 1, //num_altsetting
- (usb_iface_assoc_descriptor*)0, //iface_assoc
- &iface[Interface::I_MASS_STORAGE] //altsetting
- },
- };
+ {
+ {
+ (uint8_t *)0,
+ 1,
+ (usb_iface_assoc_descriptor*)0,
+ &iface[Interface::I_KEYBOARD]
+ },
+
+ {
+ (uint8_t *)0,
+ 1,
+ (usb_iface_assoc_descriptor*)0,
+ &iface[Interface::I_MASS_STORAGE]
+ },
+
+ };
static constexpr struct usb_config_descriptor config_descr =
{
- USB_DT_CONFIGURATION_SIZE, //bLength
- USB_DT_CONFIGURATION, //bDescriptorType
- 0, //wTotalLength
- 2, //bNumInterfaces
- 1, //bConfigurationValue
- 0, //iConfiguration
- 0x80, //bmAttributes
- 0x50, //bMaxPower
- ifaces
+ USB_DT_CONFIGURATION_SIZE,
+ USB_DT_CONFIGURATION,
+ 0,
+ 2, 1, 0, 0x80, 0x50,
+ ifaces
};
UsbCompositeDescriptors() {}
diff --git a/emb/pastilda/usb/usb_host/usbh_host.cpp b/emb/pastilda/usb/usb_host/usbh_host.cpp
index 4a8f559..9faaaaf 100644
--- a/emb/pastilda/usb/usb_host/usbh_host.cpp
+++ b/emb/pastilda/usb/usb_host/usbh_host.cpp
@@ -3,7 +3,10 @@
* hosted at http://github.com/thirdpin/pastilda
*
* Copyright (C) 2016 Third Pin LLC
- * Written by Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ *
+ * Written by:
+ * Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ * Dmitrii Lisin <mrlisdim@ya.ru>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,21 +22,19 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <usb/usb_host/usbh_host.h>
+#include "usbh_host.h"
constexpr hid_kbd_config_t USB_host::kbd_config;
constexpr usbh_dev_driver_t* USB_host::device_drivers[];
USB_host *usb_host_pointer;
-USB_host::USB_host(redirect _redirect_callback, control_interception _control_interception_callback)
+USB_host::USB_host(callback_func _callback)
{
usb_host_pointer = this;
- redirect_callback = _redirect_callback;
- control_interception_callback = _control_interception_callback;
+ callback = _callback;
timer_setup();
oth_hs_setup();
-
hid_kbd_driver_init(&kbd_config);
usbh_init(usbh_lld_stm32f4_drivers, device_drivers);
}
@@ -46,12 +47,7 @@ void USB_host::poll()
void USB_host::kbd_in_message_handler(uint8_t data_len, const uint8_t *data)
{
- if ((data[0] == 0x03) && data[2] == 0x35) {
- control_interception_callback();
- }
- else {
- redirect_callback((uint8_t*)data, data_len);
- }
+ callback((uint8_t*)data, data_len);
}
void USB_host::timer_setup()
diff --git a/emb/pastilda/usb/usb_host/usbh_host.h b/emb/pastilda/usb/usb_host/usbh_host.h
index 868026b..b5cbca9 100644
--- a/emb/pastilda/usb/usb_host/usbh_host.h
+++ b/emb/pastilda/usb/usb_host/usbh_host.h
@@ -3,7 +3,10 @@
* hosted at http://github.com/thirdpin/pastilda
*
* Copyright (C) 2016 Third Pin LLC
- * Written by Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ *
+ * Written by:
+ * Anastasiia Lazareva <a.lazareva@thirdpin.ru>
+ * Dmitrii Lisin <mrlisdim@ya.ru>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -39,16 +42,14 @@ constexpr uint8_t USB_HOST_TIMER_NUMBER = 6;
constexpr uint16_t USB_HOST_TIMER_PRESCALER = (8400 - 1);
constexpr uint16_t USB_HOST_TIMER_PERIOD = (65535);
-typedef void (*redirect)(uint8_t *data, uint8_t len);
-typedef void (*control_interception)();
+typedef void (*callback_func)(uint8_t *data, uint8_t len);
-static redirect redirect_callback;
-static control_interception control_interception_callback;
+static callback_func callback;
class USB_host
{
public:
- USB_host(redirect redirect_callback, control_interception control_interception_callback);
+ USB_host(callback_func callback);
void poll();
static void kbd_in_message_handler(uint8_t data_len, const uint8_t *data);
diff --git a/lib/etl/algorithm.h b/lib/etl/algorithm.h
new file mode 100644
index 0000000..f3afa52
--- /dev/null
+++ b/lib/etl/algorithm.h
@@ -0,0 +1,474 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_ALGORITHM__
+#define __ETL_ALGORITHM__
+
+///\defgroup algorithm algorithm
+/// Reverse engineered algorithms from C++ 0x11
+///\ingroup utilities
+
+#include <algorithm>
+#include <iterator>
+#include <utility>
+#include <functional>
+#include <stdint.h>
+
+#include "type_traits.h"
+
+namespace etl
+{
+ //***************************************************************************
+ /// Finds the greatest and the smallest element in the range (begin, end).<br>
+ ///<a href="http://en.cppreference.com/w/cpp/algorithm/minmax_element"></a>
+ ///\ingroup algorithm
+ //***************************************************************************
+ template <typename TIterator, typename TCompare>
+ std::pair<TIterator, TIterator> minmax_element(TIterator begin, TIterator end, TCompare compare)
+ {
+ TIterator minimum = begin;
+ TIterator maximum = begin;
+
+ while (begin != end)
+ {
+ if (compare(*begin, *minimum))
+ {
+ minimum = begin;
+ }
+
+ if (compare(*maximum, *begin))
+ {
+ maximum = begin;
+ }
+
+ ++begin;
+ }
+
+ return std::pair<TIterator, TIterator>(minimum, maximum);
+ }
+
+ //***************************************************************************
+ /// minmax_element
+ ///\ingroup algorithm
+ ///<a href="http://en.cppreference.com/w/cpp/algorithm/minmax_element"></a>
+ //***************************************************************************
+ template <typename TIterator>
+ std::pair<TIterator, TIterator> minmax_element(TIterator begin, TIterator end)
+ {
+ typedef typename std::iterator_traits<TIterator>::value_type value_t;
+
+ return etl::minmax_element(begin, end, std::less<value_t>());
+ }
+
+ //***************************************************************************
+ /// minmax
+ ///\ingroup algorithm
+ ///<a href="http://en.cppreference.com/w/cpp/algorithm/minmax"></a>
+ //***************************************************************************
+ template <typename T>
+ std::pair<const T&, const T&> minmax(const T& a, const T& b)
+ {
+ return (b < a) ? std::pair<const T&, const T&>(b, a) : std::pair<const T&, const T&>(a, b);
+ }
+
+ //***************************************************************************
+ /// minmax
+ ///\ingroup algorithm
+ ///<a href="http://en.cppreference.com/w/cpp/algorithm/minmax"></a>
+ //***************************************************************************
+ template <typename T, typename TCompare>
+ std::pair<const T&, const T&> minmax(const T& a, const T& b, TCompare compare)
+ {
+ return compare(b, a) ? std::pair<const T&, const T&>(b, a) : std::pair<const T&, const T&>(a, b);
+ }
+
+ //***************************************************************************
+ /// is_sorted_until
+ ///\ingroup algorithm
+ ///<a href="http://en.cppreference.com/w/cpp/algorithm/is_sorted_until"></a>
+ //***************************************************************************
+ template <typename TIterator>
+ TIterator is_sorted_until(TIterator begin, TIterator end)
+ {
+ if (begin != end)
+ {
+ TIterator next = begin;
+
+ while (++next != end)
+ {
+ if (*next < *begin)
+ {
+ return next;
+ }
+
+ ++begin;
+ }
+ }
+
+ return end;
+ }
+
+ //***************************************************************************
+ /// is_sorted_until
+ ///\ingroup algorithm
+ ///<a href="http://en.cppreference.com/w/cpp/algorithm/is_sorted_until"></a>
+ //***************************************************************************
+ template <typename TIterator, typename TCompare>
+ TIterator is_sorted_until(TIterator begin, TIterator end, TCompare compare)
+ {
+ if (begin != end)
+ {
+ TIterator next = begin;
+
+ while (++next != end)
+ {
+ if (compare(*next, *begin))
+ {
+ return next;
+ }
+
+ ++begin;
+ }
+ }
+
+ return end;
+ }
+
+ //***************************************************************************
+ /// is_sorted
+ ///\ingroup algorithm
+ ///<a href="http://en.cppreference.com/w/cpp/algorithm/is_sorted"></a>
+ //***************************************************************************
+ template<typename TIterator>
+ bool is_sorted(TIterator begin, TIterator end)
+ {
+ return etl::is_sorted_until(begin, end) == end;
+ }
+
+ //***************************************************************************
+ /// is_sorted
+ ///\ingroup algorithm
+ ///<a href="http://en.cppreference.com/w/cpp/algorithm/is_sorted"></a>
+ //***************************************************************************
+ template<typename TIterator, typename TCompare>
+ bool is_sorted(TIterator begin, TIterator end, TCompare compare)
+ {
+ return etl::is_sorted_until(begin, end, compare) == end;
+ }
+
+ //***************************************************************************
+ /// copy_n
+ ///\ingroup algorithm
+ ///<a href="http://en.cppreference.com/w/cpp/algorithm/copy_n"></a>
+ //***************************************************************************
+ template <typename TInputIterator, typename Size, typename TOutputIterator>
+ TOutputIterator copy_n(TInputIterator begin, Size count, TOutputIterator result)
+ {
+ if (count > 0)
+ {
+ for (Size i = 0; i < count; ++i)
+ {
+ *result++ = *begin++;
+ }
+ }
+
+ return result;
+ }
+
+ //***************************************************************************
+ /// copy_if
+ ///\ingroup algorithm
+ ///<a href="http://en.cppreference.com/w/cpp/algorithm/copy"></a>
+ //***************************************************************************
+ template <typename TIterator, typename TOutputIterator, typename TUnaryPredicate>
+ TOutputIterator copy_if(TIterator begin, TIterator end, TOutputIterator out, TUnaryPredicate predicate)
+ {
+ while (begin != end)
+ {
+ if (predicate(*begin))
+ {
+ *out++ = *begin;
+ }
+
+ ++begin;
+ }
+
+ return out;
+ }
+
+ //***************************************************************************
+ /// find_if_not
+ ///\ingroup algorithm
+ ///<a href="http://en.cppreference.com/w/cpp/algorithm/find"></a>
+ //***************************************************************************
+ template <typename TIterator, typename TUnaryPredicate>
+ TIterator find_if_not(TIterator begin, TIterator end, TUnaryPredicate predicate)
+ {
+ while (begin != end)
+ {
+ if (!predicate(*begin))
+ {
+ return begin;
+ }
+
+ ++begin;
+ }
+
+ return end;
+ }
+
+ //***************************************************************************
+ /// all_of
+ ///\ingroup algorithm
+ ///<a href="http://en.cppreference.com/w/cpp/algorithm/all_any_none_of"></a>
+ //***************************************************************************
+ template <typename TIterator, typename TUnaryPredicate >
+ bool all_of(TIterator begin, TIterator end, TUnaryPredicate predicate)
+ {
+ return etl::find_if_not(begin, end, predicate) == end;
+ }
+
+ //***************************************************************************
+ /// any_of
+ ///\ingroup algorithm
+ ///<a href="http://en.cppreference.com/w/cpp/algorithm/all_any_none_of"></a>
+ //***************************************************************************
+ template <typename TIterator, typename TUnaryPredicate >
+ bool any_of(TIterator begin, TIterator end, TUnaryPredicate predicate)
+ {
+ return std::find_if(begin, end, predicate) != end;
+ }
+
+ //***************************************************************************
+ /// none_of
+ ///\ingroup algorithm
+ ///<a href="http://en.cppreference.com/w/cpp/algorithm/all_any_none_of"></a>
+ //***************************************************************************
+ template <typename TIterator, typename TUnaryPredicate >
+ bool none_of(TIterator begin, TIterator end, TUnaryPredicate predicate)
+ {
+ return std::find_if(begin, end, predicate) == end;
+ }
+
+ //***************************************************************************
+ /// is_permutation
+ ///\ingroup algorithm
+ ///<a href="http://en.cppreference.com/w/cpp/algorithm/is_permutation"></a>
+ //***************************************************************************
+ template <typename TIterator1, typename TIterator2>
+ bool is_permutation(TIterator1 begin1, TIterator1 end1, TIterator2 begin2)
+ {
+ if (begin1 != end1)
+ {
+ TIterator2 end2 = begin2;
+
+ std::advance(end2, std::distance(begin1, end1));
+
+ for (TIterator1 i = begin1; i != end1; ++i)
+ {
+ if (i == std::find(begin1, i, *i))
+ {
+ int32_t n = std::count(begin2, end2, *i);
+
+ if (n == 0 || std::count(i, end1, *i) != n)
+ {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
+ //***************************************************************************
+ /// is_permutation
+ ///\ingroup algorithm
+ ///<a href="http://en.cppreference.com/w/cpp/algorithm/is_permutation"></a>
+ //***************************************************************************
+ template <typename TIterator1, typename TIterator2>
+ bool is_permutation(TIterator1 begin1, TIterator1 end1, TIterator2 begin2, TIterator2 end2)
+ {
+ if (begin1 != end1)
+ {
+ for (TIterator1 i = begin1; i != end1; ++i)
+ {
+ if (i == std::find(begin1, i, *i))
+ {
+ int32_t n = std::count(begin2, end2, *i);
+
+ if (n == 0 || std::count(i, end1, *i) != n)
+ {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
+ //***************************************************************************
+ /// is_permutation
+ ///\ingroup algorithm
+ ///<a href="http://en.cppreference.com/w/cpp/algorithm/is_permutation"></a>
+ //***************************************************************************
+ template <typename TIterator1, typename TIterator2, typename TBinaryPredicate>
+ bool is_permutation(TIterator1 begin1, TIterator1 end1, TIterator2 begin2, TBinaryPredicate predicate)
+ {
+ if (begin1 != end1)
+ {
+ TIterator2 end2 = begin2;
+
+ std::advance(end2, std::distance(begin1, end1));
+
+ for (TIterator1 i = begin1; i != end1; ++i)
+ {
+ if (i == std::find_if(begin1, i, std::bind1st(predicate, *i)))
+ {
+ int32_t n = std::count(begin2, end2, *i);
+
+ if (n == 0 || std::count(i, end1, *i) != n)
+ {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
+ //***************************************************************************
+ /// is_permutation
+ ///\ingroup algorithm
+ ///<a href="http://en.cppreference.com/w/cpp/algorithm/is_permutation"></a>
+ //***************************************************************************
+ template <typename TIterator1, typename TIterator2, typename TBinaryPredicate>
+ bool is_permutation(TIterator1 begin1, TIterator1 end1, TIterator2 begin2, TIterator2 end2, TBinaryPredicate predicate)
+ {
+ if (begin1 != end1)
+ {
+ for (TIterator1 i = begin1; i != end1; ++i)
+ {
+ if (i == std::find_if(begin1, i, std::bind1st(predicate, *i)))
+ {
+ int32_t n = std::count(begin2, end2, *i);
+
+ if (n == 0 || std::count(i, end1, *i) != n)
+ {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
+ //***************************************************************************
+ /// is_partitioned
+ ///\ingroup algorithm
+ ///<a href="http://en.cppreference.com/w/cpp/algorithm/is_partitioned"></a>
+ //***************************************************************************
+ template <typename TIterator, typename TUnaryPredicate>
+ bool is_partitioned(TIterator begin, TIterator end, TUnaryPredicate predicate)
+ {
+ while (begin != end)
+ {
+ if (!predicate(*begin++))
+ {
+ break;
+ }
+ }
+
+ while (begin != end)
+ {
+ if (predicate(*begin++))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ //***************************************************************************
+ /// partition_point
+ ///<a href="http://en.cppreference.com/w/cpp/algorithm/partition_point"></a>
+ ///\ingroup algorithm
+ //***************************************************************************
+ template <typename TIterator, typename TUnaryPredicate>
+ TIterator partition_point(TIterator begin, TIterator end, TUnaryPredicate predicate)
+ {
+ while (begin != end)
+ {
+ if (!predicate(*begin))
+ {
+ return begin;
+ }
+
+ ++begin;
+ }
+
+ return begin;
+ }
+
+ //***************************************************************************
+ /// Copies the elements from the range (begin, end) to two different ranges
+ /// depending on the value returned by the predicate.<br>
+ ///<a href="http://en.cppreference.com/w/cpp/algorithm/partition_copy"></a>
+ ///\ingroup algorithm
+ //***************************************************************************
+ template <typename TSource, typename TDestinationTrue, typename TDestinationFalse, typename TUnaryPredicate>
+ std::pair<TDestinationTrue, TDestinationFalse> partition_copy(TSource begin,
+ TSource end,
+ TDestinationTrue destination_true,
+ TDestinationFalse destination_false,
+ TUnaryPredicate predicate)
+ {
+ while (begin != end)
+ {
+ if (predicate(*begin))
+ {
+ *destination_true++ = *begin++;
+ }
+ else
+ {
+ *destination_false++ = *begin++;
+ }
+ }
+
+ return std::pair<TDestinationTrue, TDestinationFalse>(destination_true, destination_false);
+ }
+}
+
+#endif
+
diff --git a/lib/etl/alignment.h b/lib/etl/alignment.h
new file mode 100644
index 0000000..69ebbf5
--- /dev/null
+++ b/lib/etl/alignment.h
@@ -0,0 +1,193 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_ALIGNEMENT__
+#define __ETL_ALIGNEMENT__
+
+#include <stdint.h>
+
+#include "type_traits.h"
+#include "static_assert.h"
+
+///\defgroup alignment alignment
+/// Creates a variable of the specified type at the specified alignment.
+/// \ingroup utilities
+
+namespace etl
+{
+ namespace __private_alignment__
+ {
+ //***************************************************************************
+ // Matcher.
+ //***************************************************************************
+ template <const bool IS_MATCH, const size_t ALIGNMENT, typename T1 = void, typename T2 = void, typename T3 = void, typename T4 = void, typename T5 = void, typename T6 = void, typename T7 = void, typename T8 = void>
+ class type_with_alignment_matcher;
+
+ // Matching alignment.
+ template <const size_t ALIGNMENT, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
+ class type_with_alignment_matcher <true, ALIGNMENT, T1, T2, T3, T4, T5, T6, T7, T8>
+ {
+ public:
+
+ typedef T1 type;
+ };
+
+ // Non-matching alignment.
+ template <const size_t ALIGNMENT, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
+ class type_with_alignment_matcher <false, ALIGNMENT, T1, T2, T3, T4, T5, T6, T7, T8>
+ {
+ public:
+
+ typedef typename type_with_alignment_matcher<ALIGNMENT == etl::alignment_of<T2>::value, ALIGNMENT, T2, T3, T4, T5, T6, T7, T8, void>::type type;
+ };
+
+ // Non-matching alignment, non left.
+ template <const size_t ALIGNMENT>
+ class type_with_alignment_matcher <false, ALIGNMENT, void, void, void, void, void, void, void, void>
+ {
+ public:
+ };
+
+ //***************************************************************************
+ // Helper.
+ //***************************************************************************
+ template <const size_t ALIGNMENT, typename T1, typename T2 = void, typename T3 = void, typename T4 = void, typename T5 = void, typename T6 = void, typename T7 = void, typename T8 = void>
+ class type_with_alignment_helper
+ {
+ public:
+
+ typedef typename type_with_alignment_matcher<ALIGNMENT == etl::alignment_of<T1>::value, ALIGNMENT, T1, T2, T3, T4, T5, T6, T7, T8>::type type;
+ };
+ }
+
+ //***************************************************************************
+ /// Gets a type that has the same as the specified alignment.
+ ///\ingroup alignment
+ //***************************************************************************
+ template <const size_t ALIGNMENT>
+ class type_with_alignment
+ {
+ public:
+
+ typedef typename __private_alignment__::type_with_alignment_helper<ALIGNMENT, int8_t, int16_t, int32_t, int64_t, float, double, void*>::type type;
+ };
+
+ //***************************************************************************
+ /// Aligned storage
+ ///\ingroup alignment
+ //***************************************************************************
+ template <const size_t LENGTH, const size_t ALIGNMENT>
+ struct aligned_storage
+ {
+ struct type
+ {
+ /// Convert to T reference.
+ template <typename T>
+ operator T& ()
+ {
+ STATIC_ASSERT(ALIGNMENT % etl::alignment_of<T>::value == 0, "Incompatible alignment");
+ return reinterpret_cast<T&>(*data);
+ }
+
+ /// Convert to const T reference.
+ template <typename T>
+ operator const T& () const
+ {
+ STATIC_ASSERT(ALIGNMENT % etl::alignment_of<T>::value == 0, "Incompatible alignment");
+ return reinterpret_cast<const T&>(*data);
+ }
+
+ /// Convert to T pointer.
+ template <typename T>
+ operator T* ()
+ {
+ STATIC_ASSERT(ALIGNMENT % etl::alignment_of<T>::value == 0, "Incompatible alignment");
+ return reinterpret_cast<T*>(data);
+ }
+
+ /// Convert to const T pointer.
+ template <typename T>
+ operator const T* () const
+ {
+ STATIC_ASSERT(ALIGNMENT % etl::alignment_of<T>::value == 0, "Incompatible alignment");
+ return reinterpret_cast<const T*>(data);
+ }
+
+ /// Get address as T reference.
+ template <typename T>
+ T& get_reference()
+ {
+ STATIC_ASSERT(ALIGNMENT % etl::alignment_of<T>::value == 0, "Incompatible alignment");
+ return reinterpret_cast<T&>(*data);
+ }
+
+ /// Get address as const T reference.
+ template <typename T>
+ const T& get_reference() const
+ {
+ STATIC_ASSERT(ALIGNMENT % etl::alignment_of<T>::value == 0, "Incompatible alignment");
+ return reinterpret_cast<const T&>(*data);
+ }
+
+ /// Get address as T pointer.
+ template <typename T>
+ T* get_address()
+ {
+ STATIC_ASSERT(ALIGNMENT % etl::alignment_of<T>::value == 0, "Incompatible alignment");
+ return reinterpret_cast<T*>(data);
+ }
+
+ /// Get address as const T pointer.
+ template <typename T>
+ const T* get_address() const
+ {
+ STATIC_ASSERT(ALIGNMENT % etl::alignment_of<T>::value == 0, "Incompatible alignment");
+ return reinterpret_cast<const T*>(data);
+ }
+
+ union
+ {
+ uint8_t data[LENGTH];
+ typename etl::type_with_alignment<ALIGNMENT>::type __etl_alignment_type__; // A POD type that has the same alignment as ALIGNMENT.
+ };
+ };
+ };
+
+ //***************************************************************************
+ /// Aligned storage as
+ ///\ingroup alignment
+ //***************************************************************************
+ template <const size_t LENGTH, typename T>
+ struct aligned_storage_as : public etl::aligned_storage<LENGTH, etl::alignment_of<T>::value>
+ {
+ };
+}
+
+#endif
diff --git a/lib/etl/array.h b/lib/etl/array.h
new file mode 100644
index 0000000..f6c64a8
--- /dev/null
+++ b/lib/etl/array.h
@@ -0,0 +1,478 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_ARRAY__
+#define __ETL_ARRAY__
+
+#include <iterator>
+#include <functional>
+#include <algorithm>
+#include <stddef.h>
+
+#include "exception.h"
+#include "type_traits.h"
+#include "parameter_type.h"
+#include "static_assert.h"
+#include "error_handler.h"
+
+///\defgroup array array
+/// A replacement for std::array if you haven't got C++0x11.
+///\ingroup containers
+
+namespace etl
+{
+ //***************************************************************************
+ ///\ingroup array
+ /// The base class for array exceptions.
+ //***************************************************************************
+ class array_exception : public exception
+ {
+ public:
+
+ array_exception(string_type what, string_type file_name, numeric_type line_number)
+ : exception(what, file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ ///\ingroup array
+ /// The out of range exceptions.
+ //***************************************************************************
+ class array_out_of_range : public array_exception
+ {
+ public:
+
+ array_out_of_range(string_type file_name, numeric_type line_number)
+ : array_exception("array:range", file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ ///\ingroup array
+ /// A replacement for std::array if you haven't got C++0x11.
+ //***************************************************************************
+ template <typename T, const size_t SIZE_>
+ class array
+ {
+ private:
+
+ typedef typename parameter_type<T>::type parameter_t;
+
+ public:
+
+ enum
+ {
+ SIZE = SIZE_
+ };
+
+ typedef T value_type;
+ typedef std::size_t size_type;
+ typedef std::ptrdiff_t difference_type;
+ typedef T& reference;
+ typedef const T& const_reference;
+ typedef T* pointer;
+ typedef const T* const_pointer;
+ typedef T* iterator;
+ typedef const T* const_iterator;
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+
+ //*************************************************************************
+ // Element access
+ //*************************************************************************
+
+ //*************************************************************************
+ /// Returns a reference to the value at index 'i'.
+ ///\param i The index of the element to access.
+ //*************************************************************************
+ reference at(size_t i)
+ {
+ ETL_ASSERT(i < SIZE, ETL_ERROR(array_out_of_range));
+
+ return _buffer[i];
+ }
+
+ //*************************************************************************
+ /// Returns a const reference to the value at index 'i'.
+ ///\param i The index of the element to access.
+ //*************************************************************************
+ const_reference at(size_t i) const
+ {
+ ETL_ASSERT(i < SIZE, ETL_ERROR(array_out_of_range));
+
+ return _buffer[i];
+ }
+
+ //*************************************************************************
+ /// [] operator.
+ /// Returns a reference to the value at index 'i'.
+ ///\param i The index of the element to access.
+ //*************************************************************************
+ reference operator[](size_t i)
+ {
+ return _buffer[i];
+ }
+
+ //*************************************************************************
+ /// [] operator.
+ /// Returns a const reference to the value at index 'i'.
+ ///\param i The index of the element to access.
+ //*************************************************************************
+ const_reference operator[](size_t i) const
+ {
+ return _buffer[i];
+ }
+
+ //*************************************************************************
+ /// Returns a reference to the first element.
+ //*************************************************************************
+ reference front()
+ {
+ return _buffer[0];
+ }
+
+ //*************************************************************************
+ /// Returns a const reference to the first element.
+ //*************************************************************************
+ const_reference front() const
+ {
+ return _buffer[0];
+ }
+
+ //*************************************************************************
+ /// Returns a reference to the last element.
+ //*************************************************************************
+ reference back()
+ {
+ return _buffer[SIZE - 1];
+ }
+
+ //*************************************************************************
+ /// Returns a const reference to the last element.
+ //*************************************************************************
+ const_reference back() const
+ {
+ return _buffer[SIZE - 1];
+ }
+
+ //*************************************************************************
+ /// Returns a pointer to the first element of the internal buffer.
+ //*************************************************************************
+ pointer data()
+ {
+ return &_buffer[0];
+ }
+
+ //*************************************************************************
+ /// Returns a const pointer to the first element of the internal buffer.
+ //*************************************************************************
+ const_pointer data() const
+ {
+ return &_buffer[0];
+ }
+
+ //*************************************************************************
+ // Iterators
+ //*************************************************************************
+
+ //*************************************************************************
+ /// Returns an iterator to the beginning of the array.
+ //*************************************************************************
+ iterator begin()
+ {
+ return &_buffer[0];
+ }
+
+ //*************************************************************************
+ /// Returns a const iterator to the beginning of the array.
+ //*************************************************************************
+ const_iterator begin() const
+ {
+ return &_buffer[0];
+ }
+
+ //*************************************************************************
+ /// Returns a const iterator to the beginning of the array.
+ //*************************************************************************
+ const_iterator cbegin() const
+ {
+ return begin();
+ }
+
+ //*************************************************************************
+ /// Returns an iterator to the end of the array.
+ //*************************************************************************
+ iterator end()
+ {
+ return &_buffer[SIZE];
+ }
+
+ //*************************************************************************
+ /// Returns a const iterator to the end of the array.
+ //*************************************************************************
+ const_iterator end() const
+ {
+ return &_buffer[SIZE];
+ }
+
+ //*************************************************************************
+ // Returns a const iterator to the end of the array.
+ //*************************************************************************
+ const_iterator cend() const
+ {
+ return &_buffer[SIZE];
+ }
+
+ //*************************************************************************
+ // Returns an reverse iterator to the reverse beginning of the array.
+ //*************************************************************************
+ reverse_iterator rbegin()
+ {
+ return reverse_iterator(end());
+ }
+
+ //*************************************************************************
+ /// Returns a const reverse iterator to the reverse beginning of the array.
+ //*************************************************************************
+ const_reverse_iterator rbegin() const
+ {
+ return const_reverse_iterator(end());
+ }
+
+ //*************************************************************************
+ /// Returns a const reverse iterator to the reverse beginning of the array.
+ //*************************************************************************
+ const_reverse_iterator crbegin() const
+ {
+ return const_reverse_iterator(end());
+ }
+
+ //*************************************************************************
+ /// Returns a reverse iterator to the end of the array.
+ //*************************************************************************
+ reverse_iterator rend()
+ {
+ return reverse_iterator(begin());
+ }
+
+ //*************************************************************************
+ /// Returns a const reverse iterator to the end of the array.
+ //*************************************************************************
+ const_reverse_iterator rend() const
+ {
+ return const_reverse_iterator(begin());
+ }
+
+ //*************************************************************************
+ /// Returns a const reverse iterator to the end of the array.
+ //*************************************************************************
+ const_reverse_iterator crend() const
+ {
+ return const_reverse_iterator(begin());
+ }
+
+ //*************************************************************************
+ // Capacity
+ //*************************************************************************
+
+ //*************************************************************************
+ /// Returns <b>true</b> if the array size is zero.
+ //*************************************************************************
+ bool empty() const
+ {
+ return (SIZE == 0);
+ }
+
+ //*************************************************************************
+ /// Returns the size of the array.
+ //*************************************************************************
+ size_t size() const
+ {
+ return SIZE;
+ }
+
+ //*************************************************************************
+ /// Returns the maximum possible size of the array.
+ //*************************************************************************
+ size_t max_size() const
+ {
+ return SIZE;
+ }
+
+ //*************************************************************************
+ // Operations
+ //*************************************************************************
+
+ //*************************************************************************
+ /// Fills the array with the specified value.
+ ///\param value The value to fill the array with.
+ //*************************************************************************
+ void fill(parameter_t value)
+ {
+ std::fill(begin(), end(), value);
+ }
+
+ //*************************************************************************
+ /// Swaps the contents of this array and another.
+ ///\param other A reference to the other array.
+ //*************************************************************************
+ void swap(array& other)
+ {
+ for (size_t i = 0; i < SIZE; ++i)
+ {
+ std::swap(_buffer[i], other._buffer[i]);
+ }
+ }
+
+ /// The array data.
+ T _buffer[SIZE];
+ };
+
+ //*************************************************************************
+ /// Overloaded swap for etl::array<T, SIZE>
+ ///\param lhs The first array.
+ ///\param rhs The second array.
+ //*************************************************************************
+ template <typename T, const size_t SIZE>
+ void swap(etl::array<T, SIZE> &lhs, etl::array<T, SIZE> &rhs)
+ {
+ lhs.swap(rhs);
+ }
+
+ //*************************************************************************
+ /// Equal operator.
+ ///\param lhs The first array.
+ ///\param rhs The second array.
+ ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
+ //*************************************************************************
+ template <typename T, std::size_t SIZE>
+ bool operator ==(const etl::array<T, SIZE>& lhs, const etl::array<T, SIZE>& rhs)
+ {
+ return std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin());
+ }
+
+ //*************************************************************************
+ /// Not equal operator.
+ ///\param lhs The first array.
+ ///\param rhs The second array.
+ ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
+ //*************************************************************************
+ template <typename T, std::size_t SIZE>
+ bool operator !=(const etl::array<T, SIZE>& lhs, const etl::array<T, SIZE>& rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+ //*************************************************************************
+ /// Less than operator.
+ ///\param lhs The first array.
+ ///\param rhs The second array.
+ ///\return <b>true</b> if the first array is lexicographically less than the second, otherwise <b>false</b>
+ //*************************************************************************
+ template <typename T, std::size_t SIZE>
+ bool operator <(const etl::array<T, SIZE>& lhs, const etl::array<T, SIZE>& rhs)
+ {
+ return std::lexicographical_compare(lhs.cbegin(),
+ lhs.cend(),
+ rhs.cbegin(),
+ rhs.cend());
+ }
+
+ //*************************************************************************
+ /// Less than or equal operator.
+ ///\param lhs The first array.
+ ///\param rhs The second array.
+ ///\return <b>true</b> if the first array is lexicographically less than or equal to the second, otherwise <b>false</b>
+ //*************************************************************************
+ template <typename T, std::size_t SIZE>
+ bool operator <=(const etl::array<T, SIZE>& lhs, const etl::array<T, SIZE>& rhs)
+ {
+ return !(lhs > rhs);
+ }
+
+ //*************************************************************************
+ /// Greater than operator.
+ ///\param lhs The first array.
+ ///\param rhs The second array.
+ ///\return <b>true</b> if the first array is lexicographically greater than the second, otherwise <b>false</b>
+ template <typename T, std::size_t SIZE>
+ //*************************************************************************
+ bool operator >(const etl::array<T, SIZE>& lhs, const etl::array<T, SIZE>& rhs)
+ {
+ return (rhs < lhs);
+ }
+
+ //*************************************************************************
+ /// Greater than or equal operator.
+ ///\param lhs The first array.
+ ///\param rhs The second array.
+ ///\return <b>true</b> if the first array is lexicographically greater than or equal to the second, otherwise <b>false</b>
+ //*************************************************************************
+ template <typename T, std::size_t SIZE>
+ bool operator >=(const etl::array<T, SIZE>& lhs, const etl::array<T, SIZE>& rhs)
+ {
+ return !(lhs < rhs);
+ }
+
+ //*************************************************************************
+ /// Gets a reference to an element in the array.
+ ///\tparam I The index.
+ ///\tparam T The type.
+ ///\tparam MAXN The array size.
+ ///\param a The array.
+ ///\return A reference to the element
+ //*************************************************************************
+ template <std::size_t I, typename T, std::size_t MAXN>
+ inline T& get(array<T, MAXN>& a)
+ {
+ STATIC_ASSERT(I < MAXN, "Index out of bounds");
+ return a[I];
+ }
+
+ //*************************************************************************
+ /// Gets a const reference to an element in the array.
+ ///\tparam I The index.
+ ///\tparam T The type.
+ ///\tparam MAXN The array size.
+ ///\param a The array.
+ ///\return A const reference to the element
+ //*************************************************************************
+ template <std::size_t I, typename T, std::size_t MAXN>
+ inline const T& get(const array<T, MAXN>& a)
+ {
+ STATIC_ASSERT(I < MAXN, "Index out of bounds");
+ return a[I];
+ }
+}
+
+#endif
+
diff --git a/lib/etl/basic_string.h b/lib/etl/basic_string.h
new file mode 100644
index 0000000..cf216cc
--- /dev/null
+++ b/lib/etl/basic_string.h
@@ -0,0 +1,141 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_BASIC_STRING__
+#define __ETL_BASIC_STRING__
+
+#include <stddef.h>
+#include <stdint.h>
+#include <iterator>
+
+#include "ibasic_string.h"
+#include "char_traits.h"
+#include "container.h"
+#include "alignment.h"
+#include "array.h"
+
+//*****************************************************************************
+///\defgroup basic_string basic_string
+/// A basic_string with the capacity defined at compile time.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+ //***************************************************************************
+ /// A basic_string implementation that uses a fixed size buffer.
+ ///\tparam T The element type.
+ ///\tparam MAX_SIZE_ The maximum number of elements that can be stored.
+ ///\ingroup basic_string
+ //***************************************************************************
+ template <typename T, const size_t MAX_SIZE_>
+ class basic_string : public ibasic_string<T>
+ {
+ public:
+
+ static const size_t MAX_SIZE = MAX_SIZE_;
+
+ //*************************************************************************
+ /// Constructor.
+ //*************************************************************************
+ basic_string()
+ : ibasic_string<T>(reinterpret_cast<T*>(&buffer), MAX_SIZE)
+ {
+ ibasic_string<T>::initialise();
+ }
+
+ //*************************************************************************
+ /// Constructor, from null terminated text.
+ ///\param text The initial text of the basic_string.
+ //*************************************************************************
+ basic_string(const T* text)
+ : ibasic_string<T>(reinterpret_cast<T*>(&buffer), MAX_SIZE)
+ {
+ ibasic_string<T>::initialise();
+ ibasic_string<T>::assign(text, text + etl::char_traits<T>::length(text));
+ }
+
+ //*************************************************************************
+ /// Constructor, from null terminated text and count.
+ ///\param text The initial text of the basic_string.
+ ///\param count The number of characters to copy.
+ //*************************************************************************
+ basic_string(const T* text, size_t count)
+ : ibasic_string<T>(reinterpret_cast<T*>(&buffer), MAX_SIZE)
+ {
+ ibasic_string<T>::initialise();
+ ibasic_string<T>::assign(text, text + count);
+ }
+
+ //*************************************************************************
+ /// Constructor, from initial size and value.
+ ///\param initialSize The initial size of the basic_string.
+ ///\param value The value to fill the basic_string with.
+ //*************************************************************************
+ basic_string(size_t count, T c)
+ : ibasic_string<T>(reinterpret_cast<T*>(&buffer), MAX_SIZE)
+ {
+ ibasic_string<T>::initialise();
+ ibasic_string<T>::resize(count, c);
+ }
+
+ //*************************************************************************
+ /// Constructor, from an iterator range.
+ ///\tparam TIterator The iterator type.
+ ///\param first The iterator to the first element.
+ ///\param last The iterator to the last element + 1.
+ //*************************************************************************
+ template <typename TIterator>
+ basic_string(TIterator first, TIterator last)
+ : ibasic_string<T>(reinterpret_cast<T*>(&buffer), MAX_SIZE)
+ {
+ ibasic_string<T>::assign(first, last);
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ basic_string& operator = (const basic_string& rhs)
+ {
+ if (&rhs != this)
+ {
+ ibasic_string<T>::assign(rhs.cbegin(), rhs.cend());
+ }
+
+ return *this;
+ }
+
+ private:
+
+ T buffer[MAX_SIZE + 1];
+ };
+}
+
+#endif
diff --git a/lib/etl/binary.h b/lib/etl/binary.h
new file mode 100644
index 0000000..3a1be61
--- /dev/null
+++ b/lib/etl/binary.h
@@ -0,0 +1,822 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2015 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_BINARY__
+#define __ETL_BINARY__
+
+///\defgroup binary binary
+/// Binary utilities
+///\ingroup utilities
+
+#include <limits>
+#include <assert.h>
+
+#include "type_traits.h"
+#include "integral_limits.h"
+#include "static_assert.h"
+#include "log.h"
+#include "power.h"
+#include "smallest.h"
+
+namespace etl
+{
+ //***************************************************************************
+ /// Maximum value that can be contained in N bits.
+ //***************************************************************************
+ namespace __private_binary__
+ {
+ /// Helper definition for non-zero NBITS.
+ template <const size_t NBITS>
+ struct max_value_for_nbits_helper
+ {
+ typedef typename etl::smallest_uint_for_bits<NBITS>::type value_type;
+ static const value_type value = (uint64_t(1) << (NBITS - 1)) | max_value_for_nbits_helper<NBITS - 1>::value;
+ };
+
+ /// Specialisation for when NBITS == 0.
+ template <>
+ struct max_value_for_nbits_helper<0>
+ {
+ typedef etl::smallest_uint_for_bits<0>::type value_type;
+ static const value_type value = 1;
+ };
+
+ template <const size_t NBITS>
+ const typename max_value_for_nbits_helper<NBITS>::value_type max_value_for_nbits_helper<NBITS>::value;
+ }
+
+ /// Definition for non-zero NBITS.
+ template <const size_t NBITS>
+ struct max_value_for_nbits
+ {
+ typedef typename etl::smallest_uint_for_bits<NBITS>::type value_type;
+ static const value_type value = __private_binary__::max_value_for_nbits_helper<NBITS>::value;
+ };
+
+ /// Specialisation for when NBITS == 0.
+ template <>
+ struct max_value_for_nbits<0>
+ {
+ typedef etl::smallest_uint_for_bits<0>::type value_type;
+ static const value_type value = 0;
+ };
+
+ template <const size_t NBITS>
+ const typename max_value_for_nbits<NBITS>::value_type max_value_for_nbits<NBITS>::value;
+
+ //***************************************************************************
+ /// Rotate left.
+ //***************************************************************************
+ template <typename T>
+ T rotate_left(T value)
+ {
+ STATIC_ASSERT(etl::is_integral<T>::value, "Not an integral type");
+
+ const size_t SHIFT = etl::integral_limits<typename etl::make_unsigned<T>::type>::bits - 1;
+
+ return (value << 1) | (value >> SHIFT);
+ }
+
+ //***************************************************************************
+ /// Rotate left.
+ //***************************************************************************
+ template <typename T>
+ T rotate_left(T value, size_t distance)
+ {
+ STATIC_ASSERT(etl::is_integral<T>::value, "Not an integral type");
+
+ const size_t BITS = etl::integral_limits<typename etl::make_unsigned<T>::type>::bits;
+ distance %= BITS;
+ const size_t SHIFT = BITS - distance;
+
+ return (value << distance) | (value >> SHIFT);
+ }
+
+ //***************************************************************************
+ /// Rotate right.
+ //***************************************************************************
+ template <typename T>
+ T rotate_right(T value)
+ {
+ STATIC_ASSERT(etl::is_integral<T>::value, "Not an integral type");
+
+ const size_t SHIFT = etl::integral_limits<typename etl::make_unsigned<T>::type>::bits - 1;
+
+ return (value >> 1) | (value << SHIFT);
+ }
+
+ //***************************************************************************
+ /// Rotate right.
+ //***************************************************************************
+ template <typename T>
+ T rotate_right(T value, size_t distance)
+ {
+ STATIC_ASSERT(etl::is_integral<T>::value, "Not an integral type");
+
+ const size_t BITS = etl::integral_limits<typename etl::make_unsigned<T>::type>::bits;
+ distance %= BITS;
+ const size_t SHIFT = BITS - distance;
+
+ return (value >> distance) | (value << SHIFT);
+ }
+
+ //***************************************************************************
+ /// Rotate.
+ /// Positive is left, negative is right.
+ //***************************************************************************
+ template <typename T>
+ T rotate(T value, typename etl::make_signed<size_t>::type distance)
+ {
+ STATIC_ASSERT(etl::is_integral<T>::value, "Not an integral type");
+
+ T result;
+
+ if (distance > 0)
+ {
+ result = rotate_left(value, size_t(distance));
+ }
+ else
+ {
+ result = rotate_right(value, size_t(-distance));
+ }
+
+ return result;
+ }
+
+ //***************************************************************************
+ /// Reverse 8 bits.
+ //***************************************************************************
+ template <typename T>
+ typename etl::enable_if<etl::is_same<typename etl::make_unsigned<T>::type, uint8_t>::value, T>::type
+ reverse_bits(T value)
+ {
+ value = ((value & 0xAA) >> 1) | ((value & 0x55) << 1);
+ value = ((value & 0xCC) >> 2) | ((value & 0x33) << 2);
+ value = (value >> 4) | (value << 4);
+
+ return value;
+ }
+
+ //***************************************************************************
+ /// Reverse 16 bits.
+ //***************************************************************************
+ template <typename T>
+ typename etl::enable_if<etl::is_same<typename etl::make_unsigned<T>::type, uint16_t>::value, T>::type
+ reverse_bits(T value)
+ {
+ value = ((value & 0xAAAA) >> 1) | ((value & 0x5555) << 1);
+ value = ((value & 0xCCCC) >> 2) | ((value & 0x3333) << 2);
+ value = ((value & 0xF0F0) >> 4) | ((value & 0x0F0F) << 4);
+ value = (value >> 8) | (value << 8);
+
+ return value;
+ }
+
+ //***************************************************************************
+ /// Reverse 32 bits.
+ //***************************************************************************
+ template <typename T>
+ typename etl::enable_if<etl::is_same<typename etl::make_unsigned<T>::type, uint32_t>::value, T>::type
+ reverse_bits(T value)
+ {
+ value = ((value & 0xAAAAAAAA) >> 1) | ((value & 0x55555555) << 1);
+ value = ((value & 0xCCCCCCCC) >> 2) | ((value & 0x33333333) << 2);
+ value = ((value & 0xF0F0F0F0) >> 4) | ((value & 0x0F0F0F0F) << 4);
+ value = ((value & 0xFF00FF00) >> 8) | ((value & 0x00FF00FF) << 8);
+ value = (value >> 16) | (value << 16);
+
+ return value;
+ }
+
+ //***************************************************************************
+ /// Reverse 64 bits.
+ //***************************************************************************
+ template <typename T>
+ typename etl::enable_if<etl::is_same<typename etl::make_unsigned<T>::type, uint64_t>::value, T>::type
+ reverse_bits(T value)
+ {
+ value = ((value & 0xAAAAAAAAAAAAAAAA) >> 1) | ((value & 0x5555555555555555) << 1);
+ value = ((value & 0xCCCCCCCCCCCCCCCC) >> 2) | ((value & 0x3333333333333333) << 2);
+ value = ((value & 0xF0F0F0F0F0F0F0F0) >> 4) | ((value & 0x0F0F0F0F0F0F0F0F) << 4);
+ value = ((value & 0xFF00FF00FF00FF00) >> 8) | ((value & 0x00FF00FF00FF00FF) << 8);
+ value = ((value & 0xFFFF0000FFFF0000) >> 16) | ((value & 0x0000FFFF0000FFFF) << 16);
+ value = (value >> 32) | (value << 32);
+
+ return value;
+ }
+
+ //***************************************************************************
+ /// Reverse bytes 16 bit.
+ //***************************************************************************
+ template <typename T>
+ typename etl::enable_if<etl::is_same<typename etl::make_unsigned<T>::type, uint16_t>::value, T>::type
+ reverse_bytes(T value)
+ {
+ value = (value >> 8) | (value << 8);
+
+ return value;
+ }
+
+ //***************************************************************************
+ /// Reverse bytes 32 bit.
+ //***************************************************************************
+ template <typename T>
+ typename etl::enable_if<etl::is_same<typename etl::make_unsigned<T>::type, uint32_t>::value, T>::type
+ reverse_bytes(T value)
+ {
+ value = ((value & 0xFF00FF00) >> 8) | ((value & 0x00FF00FF) << 8);
+ value = (value >> 16) | (value << 16);
+
+ return value;
+ }
+
+ //***************************************************************************
+ /// Reverse bytes 64 bit.
+ //***************************************************************************
+ template <typename T>
+ typename etl::enable_if<etl::is_same<typename etl::make_unsigned<T>::type, uint64_t>::value, T>::type
+ reverse_bytes(T value)
+ {
+ value = ((value & 0xFF00FF00FF00FF00) >> 8) | ((value & 0x00FF00FF00FF00FF) << 8);
+ value = ((value & 0xFFFF0000FFFF0000) >> 16) | ((value & 0x0000FFFF0000FFFF) << 16);
+ value = (value >> 32) | (value << 32);
+
+ return value;
+ }
+
+ //***************************************************************************
+ /// Converts binary to Gray code.
+ //***************************************************************************
+ template <typename T>
+ T binary_to_gray(T value)
+ {
+ STATIC_ASSERT(etl::is_integral<T>::value, "Not an integral type");
+
+ return (value >> 1) ^ value;
+ }
+
+ //***************************************************************************
+ /// Converts Gray code to binary.
+ //***************************************************************************
+ template <typename T>
+ typename etl::enable_if<etl::is_same<typename etl::make_unsigned<T>::type, uint8_t>::value, T>::type
+ gray_to_binary(T value)
+ {
+ value ^= (value >> 4);
+ value ^= (value >> 2);
+ value ^= (value >> 1);
+
+ return value;
+ }
+
+ //***************************************************************************
+ /// Converts Gray code to binary.
+ //***************************************************************************
+ template <typename T>
+ typename etl::enable_if<etl::is_same<typename etl::make_unsigned<T>::type, uint16_t>::value, T>::type
+ gray_to_binary(T value)
+ {
+ value ^= (value >> 8);
+ value ^= (value >> 4);
+ value ^= (value >> 2);
+ value ^= (value >> 1);
+
+ return value;
+ }
+
+ //***************************************************************************
+ /// Converts Gray code to binary.
+ //***************************************************************************
+ template <typename T>
+ typename etl::enable_if<etl::is_same<typename etl::make_unsigned<T>::type, uint32_t>::value, T>::type
+ gray_to_binary(T value)
+ {
+ value ^= (value >> 16);
+ value ^= (value >> 8);
+ value ^= (value >> 4);
+ value ^= (value >> 2);
+ value ^= (value >> 1);
+
+ return value;
+ }
+
+ //***************************************************************************
+ /// Converts Gray code to binary.
+ //***************************************************************************
+ template <typename T>
+ typename etl::enable_if<etl::is_same<typename etl::make_unsigned<T>::type, uint64_t>::value, T>::type
+ gray_to_binary(T value)
+ {
+ value ^= (value >> 32);
+ value ^= (value >> 16);
+ value ^= (value >> 8);
+ value ^= (value >> 4);
+ value ^= (value >> 2);
+ value ^= (value >> 1);
+
+ return value;
+ }
+
+ //***************************************************************************
+ /// Count set bits. 8 bits.
+ //***************************************************************************
+ template <typename T>
+ typename etl::enable_if<etl::is_same<typename etl::make_unsigned<T>::type, uint8_t>::value, size_t>::type
+ count_bits(T value)
+ {
+ uint32_t count;
+ static const int S[] = { 1, 2, 4 };
+ static const uint8_t B[] = { 0x55, 0x33, 0x0F };
+
+ count = value - ((value >> 1) & B[0]);
+ count = ((count >> S[1]) & B[1]) + (count & B[1]);
+ count = ((count >> S[2]) + count) & B[2];
+
+ return count;
+ }
+
+ //***************************************************************************
+ /// Count set bits. 16 bits.
+ //***************************************************************************
+ template <typename T>
+ typename etl::enable_if<etl::is_same<typename etl::make_unsigned<T>::type, uint16_t>::value, size_t>::type
+ count_bits(T value)
+ {
+ uint32_t count;
+ static const int S[] = { 1, 2, 4, 8 };
+ static const uint16_t B[] = { 0x5555, 0x3333, 0x0F0F, 0x00FF };
+
+ count = value - ((value >> 1) & B[0]);
+ count = ((count >> S[1]) & B[1]) + (count & B[1]);
+ count = ((count >> S[2]) + count) & B[2];
+ count = ((count >> S[3]) + count) & B[3];
+
+ return count;
+ }
+
+ //***************************************************************************
+ /// Count set bits. 32 bits.
+ //***************************************************************************
+ template <typename T>
+ typename etl::enable_if<etl::is_same<typename etl::make_unsigned<T>::type, uint32_t>::value, size_t>::type
+ count_bits(T value)
+ {
+ uint32_t count;
+ static const int S[] = { 1, 2, 4, 8, 16 };
+ static const uint32_t B[] = { 0x55555555, 0x33333333, 0x0F0F0F0F, 0x00FF00FF, 0x0000FFFF };
+
+ count = value - ((value >> 1) & B[0]);
+ count = ((count >> S[1]) & B[1]) + (count & B[1]);
+ count = ((count >> S[2]) + count) & B[2];
+ count = ((count >> S[3]) + count) & B[3];
+ count = ((count >> S[4]) + count) & B[4];
+
+ return count;
+ }
+
+ //***************************************************************************
+ /// Count set bits. 64 bits.
+ //***************************************************************************
+ template <typename T>
+ typename etl::enable_if<etl::is_same<typename etl::make_unsigned<T>::type, uint64_t>::value, size_t>::type
+ count_bits(T value)
+ {
+ uint64_t count;
+ static const int S[] = { 1, 2, 4, 8, 16, 32 };
+ static const uint64_t B[] = { 0x5555555555555555, 0x3333333333333333, 0x0F0F0F0F0F0F0F0F, 0x00FF00FF00FF00FF, 0x0000FFFF0000FFFF, 0x00000000FFFFFFFF };
+
+ count = value - ((value >> 1) & B[0]);
+ count = ((count >> S[1]) & B[1]) + (count & B[1]);
+ count = ((count >> S[2]) + count) & B[2];
+ count = ((count >> S[3]) + count) & B[3];
+ count = ((count >> S[4]) + count) & B[4];
+ count = ((count >> S[5]) + count) & B[5];
+
+ return size_t(count);
+ }
+
+ //***************************************************************************
+ /// Parity. 8bits. 0 = even, 1 = odd
+ //***************************************************************************
+ template <typename T>
+ typename etl::enable_if<etl::is_same<typename etl::make_unsigned<T>::type, uint8_t>::value, size_t>::type
+ parity(T value)
+ {
+ value ^= value >> 4;
+ value &= 0x0F;
+ return (0x6996 >> value) & 1;
+ }
+
+ //***************************************************************************
+ /// Parity. 16bits. 0 = even, 1 = odd
+ //***************************************************************************
+ template <typename T>
+ typename etl::enable_if<etl::is_same<typename etl::make_unsigned<T>::type, uint16_t>::value, size_t>::type
+ parity(T value)
+ {
+ value ^= value >> 8;
+ value ^= value >> 4;
+ value &= 0x0F;
+ return (0x6996 >> value) & 1;
+ }
+
+ //***************************************************************************
+ /// Parity. 32bits. 0 = even, 1 = odd
+ //***************************************************************************
+ template <typename T>
+ typename etl::enable_if<etl::is_same<typename etl::make_unsigned<T>::type, uint32_t>::value, size_t>::type
+ parity(T value)
+ {
+ value ^= value >> 16;
+ value ^= value >> 8;
+ value ^= value >> 4;
+ value &= 0x0F;
+ return (0x6996 >> value) & 1;
+ }
+
+ //***************************************************************************
+ /// Parity. 64bits. 0 = even, 1 = odd
+ //***************************************************************************
+ template <typename T>
+ typename etl::enable_if<etl::is_same<typename etl::make_unsigned<T>::type, uint64_t>::value, size_t>::type
+ parity(T value)
+ {
+ value ^= value >> 32;
+ value ^= value >> 16;
+ value ^= value >> 8;
+ value ^= value >> 4;
+ value &= 0x0F;
+ return (0x69966996 >> value) & 1;
+ }
+
+ //***************************************************************************
+ /// Fold a binary number down to a set number of bits using XOR.
+ //***************************************************************************
+ template <typename TReturn, const size_t NBITS, typename TValue>
+ TReturn fold_bits(TValue value)
+ {
+ STATIC_ASSERT(integral_limits<TReturn>::bits >= NBITS, "Return type too small to hold result");
+
+ const TValue mask = etl::power<2, NBITS>::value - 1;
+ const size_t shift = NBITS;
+
+ // Fold the value down to fit the width.
+ TReturn folded_value = 0;
+
+ // Keep shifting down and XORing the lower bits.
+ while (value >= etl::max_value_for_nbits<NBITS>::value)
+ {
+ folded_value ^= value & mask;
+ value >>= shift;
+ }
+
+ // Fold the remaining bits.
+ folded_value ^= value & mask;
+
+ return folded_value;
+ }
+
+ //***************************************************************************
+ /// Sign extend.
+ /// Converts an N bit binary number, where bit N-1 is the sign bit, to a signed integral type.
+ //***************************************************************************
+ template <typename TReturn, const size_t NBITS, typename TValue>
+ TReturn sign_extend(TValue value)
+ {
+ STATIC_ASSERT(etl::is_integral<TValue>::value, "TValue not an integral type");
+ STATIC_ASSERT(etl::is_integral<TReturn>::value, "TReturn not an integral type");
+ STATIC_ASSERT(etl::is_signed<TReturn>::value, "TReturn not a signed type");
+ STATIC_ASSERT(NBITS <= std::numeric_limits<TReturn>::digits, "NBITS too large for return type");
+
+ typedef typename etl::make_unsigned<TReturn>::type mask_t;
+
+ mask_t negative = (1 << (NBITS - 1));
+ TReturn signed_value = value;
+
+ if ((signed_value & negative) != 0)
+ {
+ mask_t sign_bits = ~((1 << NBITS) - 1);
+ signed_value = value | sign_bits;
+ }
+
+ return signed_value;
+ }
+
+ //***************************************************************************
+ /// Sign extend.
+ /// Converts an N bit binary number, where bit N-1 is the sign bit, to a signed integral type.
+ //***************************************************************************
+ template <typename TReturn, typename TValue>
+ TReturn sign_extend(TValue value, const size_t NBITS)
+ {
+ STATIC_ASSERT(etl::is_integral<TValue>::value, "TValue not an integral type");
+ STATIC_ASSERT(etl::is_integral<TReturn>::value, "TReturn not an integral type");
+ STATIC_ASSERT(etl::is_signed<TReturn>::value, "TReturn not a signed type");
+ assert(NBITS <= std::numeric_limits<TReturn>::digits);
+
+ typedef typename etl::make_unsigned<TReturn>::type mask_t;
+
+ mask_t negative = (TReturn(1) << (NBITS - 1));
+ TReturn signed_value = value;
+
+ if ((signed_value & negative) != 0)
+ {
+ mask_t sign_bits = ~((1 << NBITS) - 1);
+ signed_value = value | sign_bits;
+ }
+
+ return signed_value;
+ }
+
+ //***************************************************************************
+ /// 8 bit binary constants.
+ //***************************************************************************
+ enum binary_constant
+ {
+ b00000000 = 0,
+ b00000001 = 1,
+ b00000010 = 2,
+ b00000011 = 3,
+ b00000100 = 4,
+ b00000101 = 5,
+ b00000110 = 6,
+ b00000111 = 7,
+ b00001000 = 8,
+ b00001001 = 9,
+ b00001010 = 10,
+ b00001011 = 11,
+ b00001100 = 12,
+ b00001101 = 13,
+ b00001110 = 14,
+ b00001111 = 15,
+ b00010000 = 16,
+ b00010001 = 17,
+ b00010010 = 18,
+ b00010011 = 19,
+ b00010100 = 20,
+ b00010101 = 21,
+ b00010110 = 22,
+ b00010111 = 23,
+ b00011000 = 24,
+ b00011001 = 25,
+ b00011010 = 26,
+ b00011011 = 27,
+ b00011100 = 28,
+ b00011101 = 29,
+ b00011110 = 30,
+ b00011111 = 31,
+ b00100000 = 32,
+ b00100001 = 33,
+ b00100010 = 34,
+ b00100011 = 35,
+ b00100100 = 36,
+ b00100101 = 37,
+ b00100110 = 38,
+ b00100111 = 39,
+ b00101000 = 40,
+ b00101001 = 41,
+ b00101010 = 42,
+ b00101011 = 43,
+ b00101100 = 44,
+ b00101101 = 45,
+ b00101110 = 46,
+ b00101111 = 47,
+ b00110000 = 48,
+ b00110001 = 49,
+ b00110010 = 50,
+ b00110011 = 51,
+ b00110100 = 52,
+ b00110101 = 53,
+ b00110110 = 54,
+ b00110111 = 55,
+ b00111000 = 56,
+ b00111001 = 57,
+ b00111010 = 58,
+ b00111011 = 59,
+ b00111100 = 60,
+ b00111101 = 61,
+ b00111110 = 62,
+ b00111111 = 63,
+ b01000000 = 64,
+ b01000001 = 65,
+ b01000010 = 66,
+ b01000011 = 67,
+ b01000100 = 68,
+ b01000101 = 69,
+ b01000110 = 70,
+ b01000111 = 71,
+ b01001000 = 72,
+ b01001001 = 73,
+ b01001010 = 74,
+ b01001011 = 75,
+ b01001100 = 76,
+ b01001101 = 77,
+ b01001110 = 78,
+ b01001111 = 79,
+ b01010000 = 80,
+ b01010001 = 81,
+ b01010010 = 82,
+ b01010011 = 83,
+ b01010100 = 84,
+ b01010101 = 85,
+ b01010110 = 86,
+ b01010111 = 87,
+ b01011000 = 88,
+ b01011001 = 89,
+ b01011010 = 90,
+ b01011011 = 91,
+ b01011100 = 92,
+ b01011101 = 93,
+ b01011110 = 94,
+ b01011111 = 95,
+ b01100000 = 96,
+ b01100001 = 97,
+ b01100010 = 98,
+ b01100011 = 99,
+ b01100100 = 100,
+ b01100101 = 101,
+ b01100110 = 102,
+ b01100111 = 103,
+ b01101000 = 104,
+ b01101001 = 105,
+ b01101010 = 106,
+ b01101011 = 107,
+ b01101100 = 108,
+ b01101101 = 109,
+ b01101110 = 110,
+ b01101111 = 111,
+ b01110000 = 112,
+ b01110001 = 113,
+ b01110010 = 114,
+ b01110011 = 115,
+ b01110100 = 116,
+ b01110101 = 117,
+ b01110110 = 118,
+ b01110111 = 119,
+ b01111000 = 120,
+ b01111001 = 121,
+ b01111010 = 122,
+ b01111011 = 123,
+ b01111100 = 124,
+ b01111101 = 125,
+ b01111110 = 126,
+ b01111111 = 127,
+ b10000000 = 128,
+ b10000001 = 129,
+ b10000010 = 130,
+ b10000011 = 131,
+ b10000100 = 132,
+ b10000101 = 133,
+ b10000110 = 134,
+ b10000111 = 135,
+ b10001000 = 136,
+ b10001001 = 137,
+ b10001010 = 138,
+ b10001011 = 139,
+ b10001100 = 140,
+ b10001101 = 141,
+ b10001110 = 142,
+ b10001111 = 143,
+ b10010000 = 144,
+ b10010001 = 145,
+ b10010010 = 146,
+ b10010011 = 147,
+ b10010100 = 148,
+ b10010101 = 149,
+ b10010110 = 150,
+ b10010111 = 151,
+ b10011000 = 152,
+ b10011001 = 153,
+ b10011010 = 154,
+ b10011011 = 155,
+ b10011100 = 156,
+ b10011101 = 157,
+ b10011110 = 158,
+ b10011111 = 159,
+ b10100000 = 160,
+ b10100001 = 161,
+ b10100010 = 162,
+ b10100011 = 163,
+ b10100100 = 164,
+ b10100101 = 165,
+ b10100110 = 166,
+ b10100111 = 167,
+ b10101000 = 168,
+ b10101001 = 169,
+ b10101010 = 170,
+ b10101011 = 171,
+ b10101100 = 172,
+ b10101101 = 173,
+ b10101110 = 174,
+ b10101111 = 175,
+ b10110000 = 176,
+ b10110001 = 177,
+ b10110010 = 178,
+ b10110011 = 179,
+ b10110100 = 180,
+ b10110101 = 181,
+ b10110110 = 182,
+ b10110111 = 183,
+ b10111000 = 184,
+ b10111001 = 185,
+ b10111010 = 186,
+ b10111011 = 187,
+ b10111100 = 188,
+ b10111101 = 189,
+ b10111110 = 190,
+ b10111111 = 191,
+ b11000000 = 192,
+ b11000001 = 193,
+ b11000010 = 194,
+ b11000011 = 195,
+ b11000100 = 196,
+ b11000101 = 197,
+ b11000110 = 198,
+ b11000111 = 199,
+ b11001000 = 200,
+ b11001001 = 201,
+ b11001010 = 202,
+ b11001011 = 203,
+ b11001100 = 204,
+ b11001101 = 205,
+ b11001110 = 206,
+ b11001111 = 207,
+ b11010000 = 208,
+ b11010001 = 209,
+ b11010010 = 210,
+ b11010011 = 211,
+ b11010100 = 212,
+ b11010101 = 213,
+ b11010110 = 214,
+ b11010111 = 215,
+ b11011000 = 216,
+ b11011001 = 217,
+ b11011010 = 218,
+ b11011011 = 219,
+ b11011100 = 220,
+ b11011101 = 221,
+ b11011110 = 222,
+ b11011111 = 223,
+ b11100000 = 224,
+ b11100001 = 225,
+ b11100010 = 226,
+ b11100011 = 227,
+ b11100100 = 228,
+ b11100101 = 229,
+ b11100110 = 230,
+ b11100111 = 231,
+ b11101000 = 232,
+ b11101001 = 233,
+ b11101010 = 234,
+ b11101011 = 235,
+ b11101100 = 236,
+ b11101101 = 237,
+ b11101110 = 238,
+ b11101111 = 239,
+ b11110000 = 240,
+ b11110001 = 241,
+ b11110010 = 242,
+ b11110011 = 243,
+ b11110100 = 244,
+ b11110101 = 245,
+ b11110110 = 246,
+ b11110111 = 247,
+ b11111000 = 248,
+ b11111001 = 249,
+ b11111010 = 250,
+ b11111011 = 251,
+ b11111100 = 252,
+ b11111101 = 253,
+ b11111110 = 254,
+ b11111111 = 255
+ };
+}
+
+#endif
diff --git a/lib/etl/bitset.h b/lib/etl/bitset.h
new file mode 100644
index 0000000..5d4fbcf
--- /dev/null
+++ b/lib/etl/bitset.h
@@ -0,0 +1,344 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_BITSET__
+#define __ETL_BITSET__
+
+#include <algorithm>
+#include <iterator>
+#include <string.h>
+#include <stddef.h>
+
+#include "platform.h"
+#include "integral_limits.h"
+#include "algorithm.h"
+#include "nullptr.h"
+#include "log.h"
+#include "ibitset.h"
+
+#define ETL_NO_CHECKS
+#include "error_handler.h"
+
+#if defined(ETL_COMPILER_KEIL)
+#pragma diag_suppress 1300
+#endif
+
+//*****************************************************************************
+///\defgroup bitset bitset
+/// Similar to std::bitset but without requiring std::string.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+ //*************************************************************************
+ /// The class emulates an array of bool elements, but optimized for space allocation.
+ /// Will accommodate any number of bits.
+ /// Does not use std::string.
+ ///\tparam N The number of bits.
+ ///\ingroup bitset
+ //*************************************************************************
+ template <const size_t MAXN>
+ class bitset : public ibitset
+ {
+
+ static const size_t ARRAY_SIZE = (MAXN % BITS_PER_ELEMENT == 0) ? MAXN / BITS_PER_ELEMENT : MAXN / BITS_PER_ELEMENT + 1;
+
+ public:
+
+ static const size_t ALLOCATED_BITS = ARRAY_SIZE * BITS_PER_ELEMENT;
+
+ public:
+
+ //*************************************************************************
+ /// Default constructor.
+ //*************************************************************************
+ bitset()
+ : ibitset(MAXN, ARRAY_SIZE, data)
+ {
+ reset();
+ }
+
+ //*************************************************************************
+ /// Copy constructor.
+ //*************************************************************************
+ bitset(const bitset<MAXN>& other)
+ : ibitset(MAXN, ARRAY_SIZE, data)
+ {
+ etl::copy_n(other.data, ARRAY_SIZE, data);
+ }
+
+ //*************************************************************************
+ /// Construct from a value.
+ //*************************************************************************
+ bitset(unsigned long long value)
+ : ibitset(MAXN, ARRAY_SIZE, data)
+ {
+ initialise(value);
+ }
+
+ //*************************************************************************
+ /// Construct from a string.
+ //*************************************************************************
+ bitset(const char* text)
+ : ibitset(MAXN, ARRAY_SIZE, data)
+ {
+ set(text);
+ }
+
+ //*************************************************************************
+ /// Set all of the bits.
+ //*************************************************************************
+ bitset<MAXN>& set()
+ {
+ ibitset::set();
+ return *this;
+ }
+
+ //*************************************************************************
+ /// Set the bit at the position.
+ //*************************************************************************
+ bitset<MAXN>& set(size_t position, bool value = true)
+ {
+ ibitset::set(position, value);
+ return *this;
+ }
+
+ //*************************************************************************
+ /// Set from a string.
+ //*************************************************************************
+ bitset<MAXN>& set(const char* text)
+ {
+ ETL_ASSERT(text != 0, ETL_ERROR(bitset_nullptr));
+ ibitset::set(text);
+
+ return *this;
+ }
+
+ //*************************************************************************
+ /// Reset all of the bits.
+ //*************************************************************************
+ bitset<MAXN>& reset()
+ {
+ ibitset::reset();
+ return *this;
+ }
+
+ //*************************************************************************
+ /// Reset the bit at the position.
+ //*************************************************************************
+ bitset<MAXN>& reset(size_t position)
+ {
+ ibitset::reset(position);
+ return *this;
+ }
+
+ //*************************************************************************
+ /// Flip all of the bits.
+ //*************************************************************************
+ bitset<MAXN>& flip()
+ {
+ ibitset::flip();
+ return *this;
+ }
+
+ //*************************************************************************
+ /// Flip the bit at the position.
+ //*************************************************************************
+ bitset<MAXN>& flip(size_t position)
+ {
+ ibitset::flip(position);
+ return *this;
+ }
+
+ //*************************************************************************
+ /// operator =
+ //*************************************************************************
+ bitset<MAXN>& operator =(const bitset<MAXN>& other)
+ {
+ if (this != &other)
+ {
+ etl::copy_n(other.data, ARRAY_SIZE, data);
+ }
+
+ return *this;
+ }
+
+ //*************************************************************************
+ /// operator &=
+ //*************************************************************************
+ bitset<MAXN>& operator &=(const bitset<MAXN>& other)
+ {
+ ibitset::operator &=(other);
+ return *this;
+ }
+
+ //*************************************************************************
+ /// operator |=
+ //*************************************************************************
+ bitset<MAXN>& operator |=(const bitset<MAXN>& other)
+ {
+ ibitset::operator |=(other);
+ return *this;
+ }
+
+ //*************************************************************************
+ /// operator ^=
+ //*************************************************************************
+ bitset<MAXN>& operator ^=(const bitset<MAXN>& other)
+ {
+ ibitset::operator ^=(other);
+ return *this;
+ }
+
+ //*************************************************************************
+ /// operator ~
+ //*************************************************************************
+ bitset<MAXN> operator ~() const
+ {
+ bitset<MAXN> temp(*this);
+
+ temp.invert();
+
+ return temp;
+ }
+
+ //*************************************************************************
+ /// operator <<
+ //*************************************************************************
+ bitset<MAXN> operator<<(size_t shift) const
+ {
+ bitset<MAXN> temp(*this);
+
+ temp <<= shift;
+
+ return temp;
+ }
+
+ //*************************************************************************
+ /// operator <<=
+ //*************************************************************************
+ bitset<MAXN>& operator<<=(size_t shift)
+ {
+ ibitset::operator <<=(shift);
+ return *this;
+ }
+
+ //*************************************************************************
+ /// operator >>
+ //*************************************************************************
+ bitset<MAXN> operator>>(size_t shift) const
+ {
+ bitset<MAXN> temp(*this);
+
+ temp >>= shift;
+
+ return temp;
+ }
+
+ //*************************************************************************
+ /// operator >>=
+ //*************************************************************************
+ bitset<MAXN>& operator>>=(size_t shift)
+ {
+ ibitset::operator >>=(shift);
+ return *this;
+ }
+
+ //*************************************************************************
+ /// operator ==
+ //*************************************************************************
+ friend bool operator == (const bitset<MAXN>& lhs, const bitset<MAXN>& rhs)
+ {
+ return ibitset::is_equal(lhs, rhs);
+ }
+
+ private:
+
+ element_t data[ARRAY_SIZE];
+ };
+
+ //***************************************************************************
+ /// operator &
+ ///\ingroup bitset
+ //***************************************************************************
+ template <const size_t MAXN>
+ bitset<MAXN> operator & (const bitset<MAXN>& lhs, const bitset<MAXN>& rhs)
+ {
+ bitset<MAXN> temp(lhs);
+ temp &= rhs;
+ return temp;
+ }
+
+ //***************************************************************************
+ /// operator |
+ ///\ingroup bitset
+ //***************************************************************************
+ template<const size_t MAXN>
+ bitset<MAXN> operator | (const bitset<MAXN>& lhs, const bitset<MAXN>& rhs)
+ {
+ bitset<MAXN> temp(lhs);
+ temp |= rhs;
+ return temp;
+ }
+
+ //***************************************************************************
+ /// operator ^
+ ///\ingroup bitset
+ //***************************************************************************
+ template<const size_t MAXN>
+ bitset<MAXN> operator ^ (const bitset<MAXN>& lhs, const bitset<MAXN>& rhs)
+ {
+ bitset<MAXN> temp(lhs);
+ temp ^= rhs;
+ return temp;
+ }
+
+ //***************************************************************************
+ /// operator !=
+ ///\ingroup bitset
+ //***************************************************************************
+ template<const size_t MAXN>
+ bool operator != (const bitset<MAXN>& lhs, const bitset<MAXN>& rhs)
+ {
+ return !(lhs == rhs);
+ }
+}
+
+//*************************************************************************
+/// swap
+//*************************************************************************
+template <const size_t MAXN>
+void swap(etl::bitset<MAXN>& lhs, etl::bitset<MAXN>& rhs)
+{
+ lhs.swap(rhs);
+}
+
+#endif
diff --git a/lib/etl/bloom_filter.h b/lib/etl/bloom_filter.h
new file mode 100644
index 0000000..3407d6e
--- /dev/null
+++ b/lib/etl/bloom_filter.h
@@ -0,0 +1,189 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_BLOOM_FILTER__
+#define __ETL_BLOOM_FILTER__
+
+#include "parameter_type.h"
+#include "bitset.h"
+#include "type_traits.h"
+#include "binary.h"
+#include "log.h"
+#include "power.h"
+
+///\defgroup bloom_filter bloom_filter
+/// A Bloom filter
+///\ingroup containers
+
+namespace etl
+{
+ namespace __private_bloom_filter__
+ {
+ // Placeholder null hash for defaulted template parameters.
+ struct null_hash
+ {
+ template <typename T>
+ size_t operator ()(T)
+ {
+ return 0;
+ }
+ };
+ }
+
+ //***************************************************************************
+ /// An implementation of a bloom filter.
+ /// Allows up to three hashes to be defined.
+ /// Hashes must support the () operator and define 'argument_type'.
+ ///\tparam DESIRED_WIDTH The desired number of hash results that can be stored. Rounded up to best fit the underlying bitset.
+ ///\tparam THash1 The first hash generator class.
+ ///\tparam THash2 The second hash generator class. If omitted, uses the null hash.
+ ///\tparam THash3 The third hash generator class. If omitted, uses the null hash.
+ /// The hash classes must define <b>argument_type</b>.
+ ///\ingroup bloom_filter
+ //***************************************************************************
+ template <const size_t DESIRED_WIDTH,
+ typename THash1,
+ typename THash2 = __private_bloom_filter__::null_hash,
+ typename THash3 = __private_bloom_filter__::null_hash>
+ class bloom_filter
+ {
+ private:
+
+ typedef typename etl::parameter_type<typename THash1::argument_type>::type parameter_t;
+ typedef __private_bloom_filter__::null_hash null_hash;
+
+ public:
+
+ enum
+ {
+ // Make the most efficient use of the bitset.
+ WIDTH = etl::bitset<DESIRED_WIDTH>::ALLOCATED_BITS
+ };
+
+ //***************************************************************************
+ /// Clears the bloom filter of all entries.
+ //***************************************************************************
+ void clear()
+ {
+ flags.reset();
+ }
+
+ //***************************************************************************
+ /// Adds a key to the filter.
+ ///\param key The key to add.
+ //***************************************************************************
+ void add(parameter_t key)
+ {
+ flags.set(get_hash<THash1>(key));
+
+ if (!etl::is_same<THash2, null_hash>::value)
+ {
+ flags.set(get_hash<THash2>(key));
+ }
+
+ if (!etl::is_same<THash3, null_hash>::value)
+ {
+ flags.set(get_hash<THash3>(key));
+ }
+ }
+
+ //***************************************************************************
+ /// Tests a key to see if it exists in the filter.
+ ///\param key The key to test.
+ ///\return <b>true</b> if the key exists in the filter.
+ //***************************************************************************
+ bool exists(parameter_t key) const
+ {
+ bool exists1 = flags[get_hash<THash1>(key)];
+ bool exists2 = true;
+ bool exists3 = true;
+
+ // Do we have a second hash?
+ if (!etl::is_same<THash2, null_hash>::value)
+ {
+ exists2 = flags[get_hash<THash2>(key)];
+ }
+
+ // Do we have a third hash?
+ if (!etl::is_same<THash3, null_hash>::value)
+ {
+ exists3 = flags[get_hash<THash3>(key)];
+ }
+
+ return exists1 && exists2 && exists3;
+ }
+
+ //***************************************************************************
+ /// Returns the width of the Bloom filter.
+ //***************************************************************************
+ size_t width() const
+ {
+ return WIDTH;
+ }
+
+ //***************************************************************************
+ /// Returns the percentage of usage. Range 0 to 100.
+ //***************************************************************************
+ size_t usage() const
+ {
+ return (100 * count()) / WIDTH;
+ }
+
+ //***************************************************************************
+ /// Returns the number of filter flags set.
+ //***************************************************************************
+ size_t count() const
+ {
+ return flags.count();
+ }
+
+ private:
+
+ //***************************************************************************
+ /// Gets the hash for the key.
+ ///\param key The key.
+ ///\return The hash value.
+ //***************************************************************************
+ template <typename THash>
+ size_t get_hash(parameter_t key) const
+ {
+ size_t hash = THash()(key);
+
+ // Fold the hash down to fit the width.
+ return fold_bits<size_t, etl::log2<WIDTH>::value>(hash);
+ }
+
+ /// The Bloom filter flags.
+ etl::bitset<WIDTH> flags;
+ };
+}
+
+#endif
+
diff --git a/lib/etl/char_traits.h b/lib/etl/char_traits.h
new file mode 100644
index 0000000..6caab98
--- /dev/null
+++ b/lib/etl/char_traits.h
@@ -0,0 +1,243 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_CHAR_TRAITS__
+#define __ETL_CHAR_TRAITS__
+
+#include <algorithm>
+
+#include "platform.h"
+#include "stdint.h"
+#include "algorithm.h"
+
+//*****************************************************************************
+///\defgroup char_traits char_traits
+/// Character traits
+///\ingroup string
+//*****************************************************************************
+
+// Define the large character types if necessary.
+#ifdef NO_LARGE_CHAR_SUPPORT
+typedef int16_t char16_t;
+typedef int32_t char32_t;
+#endif
+
+namespace etl
+{
+ template<typename T> struct char_traits_types;
+
+ template<> struct char_traits_types<char>
+ {
+ typedef char char_type;
+ typedef int int_type;
+ typedef long long off_type;
+ typedef size_t pos_type;
+ typedef char state_type;
+ };
+
+ template<> struct char_traits_types<wchar_t>
+ {
+ typedef wchar_t char_type;
+ typedef wchar_t int_type;
+ typedef long long off_type;
+ typedef size_t pos_type;
+ typedef char state_type;
+ };
+
+ template<> struct char_traits_types<char16_t>
+ {
+ typedef char16_t char_type;
+ typedef uint_least16_t int_type;
+ typedef long long off_type;
+ typedef size_t pos_type;
+ typedef char state_type;
+ };
+
+ template<> struct char_traits_types<char32_t>
+ {
+ typedef char32_t char_type;
+ typedef uint_least32_t int_type;
+ typedef long long off_type;
+ typedef size_t pos_type;
+ typedef char state_type;
+ };
+
+ //***************************************************************************
+ /// Character traits for any character type.
+ //***************************************************************************
+ template<typename T>
+ struct char_traits : public char_traits_types<T>
+ {
+ typedef typename char_traits_types<T>::char_type char_type;
+ typedef typename char_traits_types<T>::int_type int_type;
+ typedef typename char_traits_types<T>::off_type off_type;
+ typedef typename char_traits_types<T>::pos_type pos_type;
+ typedef typename char_traits_types<T>::state_type state_type;
+
+ //*************************************************************************
+ static bool eq(char_type a, char_type b)
+ {
+ return a == b;
+ }
+
+ //*************************************************************************
+ static bool lt(char_type a, char_type b)
+ {
+ return a < b;
+ }
+
+ //*************************************************************************
+ static size_t length(const char_type* str)
+ {
+ size_t count = 0;
+
+ if (str != 0)
+ {
+ while (*str++ != 0)
+ {
+ ++count;
+ }
+ }
+
+ return count;
+ }
+
+ //*************************************************************************
+ static void assign(char_type& r, const char_type& c)
+ {
+ r = c;
+ }
+
+ //*************************************************************************
+ static char_type* assign(char_type* p, size_t n, char_type c)
+ {
+ if (p != 0)
+ {
+ std::fill_n(p, n, c);
+ }
+
+ return p;
+ }
+
+ //*************************************************************************
+ static char_type* move(char_type* dest, const char_type* src, size_t count)
+ {
+ if ((dest < src) || (dest > (src + count)))
+ {
+ etl::copy_n(src, src + count, dest);
+ }
+ else
+ {
+ etl::copy_n(std::reverse_iterator<char_type*>(src + count),
+ count,
+ std::reverse_iterator<char_type*>(dest + count));
+ }
+
+ return dest;
+ }
+
+ //*************************************************************************
+ static char_type* copy(char_type* dest, const char_type* src, size_t count)
+ {
+ etl::copy_n(src, src + count, dest);
+
+ return dest;
+ }
+
+ //*************************************************************************
+ static int compare(const char_type* s1, const char_type* s2, size_t count)
+ {
+ for (size_t i = 0; i < count; ++i)
+ {
+ if (*s1 < *s2)
+ {
+ return -1;
+ }
+ else if (*s1 > *s2)
+ {
+ return 1;
+ }
+
+ ++s1;
+ ++s2;
+ }
+
+ return 0;
+ }
+
+ //*************************************************************************
+ static const char_type* find(const char_type* p, size_t count, const char_type& ch)
+ {
+ for (size_t i = 0; i < count; ++i)
+ {
+ if (*p == ch)
+ {
+ return p;
+ }
+
+ ++p;
+ }
+
+ return 0;
+ }
+
+ //*************************************************************************
+ static char_type to_char_type(int_type c)
+ {
+ return static_cast<char_type>(c);
+ }
+
+ //*************************************************************************
+ static int_type to_int_type(char_type c)
+ {
+ return static_cast<int_type>(c);
+ }
+
+ //*************************************************************************
+ static bool eq_int_type(int_type c1, int_type c2)
+ {
+ return (c1 == c2);
+ }
+
+ //*************************************************************************
+ static int_type eof()
+ {
+ return -1;
+ }
+
+ //*************************************************************************
+ static int_type not_eof(int_type e)
+ {
+ return (e == eof()) ? eof() - 1 : e;
+ }
+ };
+}
+
+#endif
diff --git a/lib/etl/checksum.h b/lib/etl/checksum.h
new file mode 100644
index 0000000..b6bb0ee
--- /dev/null
+++ b/lib/etl/checksum.h
@@ -0,0 +1,200 @@
+
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+Copyright(c) 2014 jwellbelove
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_CHECKSUM__
+#define __ETL_CHECKSUM__
+
+#include <stdint.h>
+
+#include "binary.h"
+#include "frame_check_sequence.h"
+
+///\defgroup checksum Checksum calculation
+///\ingroup maths
+
+namespace etl
+{
+ //***************************************************************************
+ /// Standard addition checksum policy.
+ //***************************************************************************
+ template <typename T>
+ struct checksum_policy_sum
+ {
+ typedef T value_type;
+
+ inline T initial() const
+ {
+ return 0;
+ }
+
+ inline T add(T sum, uint8_t value) const
+ {
+ return sum + value;
+ }
+
+ inline T final(T sum) const
+ {
+ return sum;
+ }
+ };
+
+ //***************************************************************************
+ /// BSD checksum policy.
+ //***************************************************************************
+ template <typename T>
+ struct checksum_policy_bsd
+ {
+ typedef T value_type;
+
+ inline T initial() const
+ {
+ return 0;
+ }
+
+ inline T add(T sum, uint8_t value) const
+ {
+ return etl::rotate_right(sum) + value;
+ }
+
+ inline T final(T sum) const
+ {
+ return sum;
+ }
+ };
+
+ //***************************************************************************
+ /// Standard XOR checksum policy.
+ //***************************************************************************
+ template <typename T>
+ struct checksum_policy_xor
+ {
+ typedef T value_type;
+
+ inline T initial() const
+ {
+ return 0;
+ }
+
+ inline T add(T sum, uint8_t value) const
+ {
+ return sum ^ value;
+ }
+
+ inline T final(T sum) const
+ {
+ return sum;
+ }
+ };
+
+ //*************************************************************************
+ /// Standard Checksum.
+ //*************************************************************************
+ template <typename T>
+ class checksum : public etl::frame_check_sequence<etl::checksum_policy_sum<T> >
+ {
+ public:
+
+ //*************************************************************************
+ /// Default constructor.
+ //*************************************************************************
+ checksum()
+ {
+ this->reset();
+ }
+
+ //*************************************************************************
+ /// Constructor from range.
+ /// \param begin Start of the range.
+ /// \param end End of the range.
+ //*************************************************************************
+ template<typename TIterator>
+ checksum(TIterator begin, const TIterator end)
+ {
+ this->reset();
+ this->add(begin, end);
+ }
+ };
+
+ //*************************************************************************
+ /// BSD Checksum.
+ //*************************************************************************
+ template <typename T>
+ class bsd_checksum : public etl::frame_check_sequence<etl::checksum_policy_bsd<T> >
+ {
+ public:
+
+ //*************************************************************************
+ /// Default constructor.
+ //*************************************************************************
+ bsd_checksum()
+ {
+ this->reset();
+ }
+
+ //*************************************************************************
+ /// Constructor from range.
+ /// \param begin Start of the range.
+ /// \param end End of the range.
+ //*************************************************************************
+ template<typename TIterator>
+ bsd_checksum(TIterator begin, const TIterator end)
+ {
+ this->reset();
+ this->add(begin, end);
+ }
+ };
+
+ //*************************************************************************
+ /// XOR Checksum.
+ //*************************************************************************
+ template <typename T>
+ class xor_checksum : public etl::frame_check_sequence<etl::checksum_policy_xor<T> >
+ {
+ public:
+
+ //*************************************************************************
+ /// Default constructor.
+ //*************************************************************************
+ xor_checksum()
+ {
+ this->reset();
+ }
+
+ //*************************************************************************
+ /// Constructor from range.
+ /// \param begin Start of the range.
+ /// \param end End of the range.
+ //*************************************************************************
+ template<typename TIterator>
+ xor_checksum(TIterator begin, const TIterator end)
+ {
+ this->reset();
+ this->add(begin, end);
+ }
+ };
+}
+
+#endif
diff --git a/lib/etl/container.h b/lib/etl/container.h
new file mode 100644
index 0000000..d03cddc
--- /dev/null
+++ b/lib/etl/container.h
@@ -0,0 +1,297 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_CONTAINER__
+#define __ETL_CONTAINER__
+
+#include <stddef.h>
+#include <iterator>
+
+///\defgroup container container
+///\ingroup utilities
+
+namespace etl
+{
+ //*****************************************************************************
+ /// Get the 'begin' iterator.
+ ///\ingroup container
+ //*****************************************************************************
+ template<typename TContainer>
+ typename TContainer::iterator begin(TContainer& container)
+ {
+ return container.begin();
+ }
+
+ //*****************************************************************************
+ /// Get the 'begin' const_iterator for a container.
+ ///\ingroup container
+ //*****************************************************************************
+ template<typename TContainer>
+ typename TContainer::const_iterator begin(const TContainer& container)
+ {
+ return container.begin();
+ }
+
+ //*****************************************************************************
+ /// Get the 'begin' const_iterator for a container.
+ ///\ingroup container
+ //*****************************************************************************
+ template<typename TContainer>
+ typename TContainer::const_iterator cbegin(const TContainer& container)
+ {
+ return container.cbegin();
+ }
+
+ //*****************************************************************************
+ /// Get the 'begin' reverse_iterator for a container.
+ ///\ingroup container
+ //*****************************************************************************
+ template<typename TContainer>
+ typename TContainer::reverse_iterator rbegin(const TContainer& container)
+ {
+ return container.rbegin();
+ }
+
+ //*****************************************************************************
+ /// Get the 'begin' reverse_iterator for a container.
+ ///\ingroup container
+ //*****************************************************************************
+ template<typename TContainer>
+ typename TContainer::reverse_iterator crbegin(const TContainer& container)
+ {
+ return container.crbegin();
+ }
+
+ //*****************************************************************************
+ /// Get the 'end' iterator for a container.
+ ///\ingroup container
+ //*****************************************************************************
+ template<typename TContainer>
+ typename TContainer::iterator end(TContainer& container)
+ {
+ return container.end();
+ }
+
+ //*****************************************************************************
+ /// Get the 'end' const_iterator for a container.
+ ///\ingroup container
+ //*****************************************************************************
+ template<typename TContainer>
+ typename TContainer::const_iterator end(const TContainer& container)
+ {
+ return container.end();
+ }
+
+ //*****************************************************************************
+ /// Get the 'end' const_iterator for a container.
+ ///\ingroup container
+ //*****************************************************************************
+ template<typename TContainer>
+ typename TContainer::const_iterator cend(const TContainer& container)
+ {
+ return container.cend();
+ }
+
+ //*****************************************************************************
+ /// Get the 'end' reverse_iterator for a container.
+ ///\ingroup container
+ //*****************************************************************************
+ template<typename TContainer>
+ typename TContainer::const_iterator rend(const TContainer& container)
+ {
+ return container.rend();
+ }
+
+ //*****************************************************************************
+ /// Get the 'end' reverse_iterator for a container.
+ ///\ingroup container
+ //*****************************************************************************
+ template<typename TContainer>
+ typename TContainer::reverse_iterator crend(const TContainer& container)
+ {
+ return container.crend();
+ }
+
+ //*****************************************************************************
+ /// Get the 'begin' pointer for an array.
+ ///\ingroup container
+ //*****************************************************************************
+ template<typename TValue, const size_t ARRAY_SIZE>
+ TValue* begin(TValue(&data)[ARRAY_SIZE])
+ {
+ return &data[0];
+ }
+
+ //*****************************************************************************
+ /// Get the 'begin' const iterator for an array.
+ ///\ingroup container
+ //*****************************************************************************
+ template<typename TValue, const size_t ARRAY_SIZE>
+ const TValue* begin(const TValue(&data)[ARRAY_SIZE])
+ {
+ return &data[0];
+ }
+
+ //*****************************************************************************
+ /// Get the 'begin' const iterator for an array.
+ ///\ingroup container
+ //*****************************************************************************
+ template<typename TValue, const size_t ARRAY_SIZE>
+ const TValue* cbegin(const TValue(&data)[ARRAY_SIZE])
+ {
+ return &data[0];
+ }
+
+ //*****************************************************************************
+ /// Get the 'begin' reverse_iterator for an array.
+ ///\ingroup container
+ //*****************************************************************************
+ template<typename TValue, const size_t ARRAY_SIZE>
+ std::reverse_iterator<TValue*> rbegin(const TValue(&data)[ARRAY_SIZE])
+ {
+ return std::reverse_iterator<TValue*>(&data[ARRAY_SIZE]);
+ }
+
+ //*****************************************************************************
+ /// Get the 'begin' const reverse_iterator for an array.
+ ///\ingroup container
+ //*****************************************************************************
+ template<typename TValue, const size_t ARRAY_SIZE>
+ std::reverse_iterator<const TValue*> crbegin(const TValue(&data)[ARRAY_SIZE])
+ {
+ return std::reverse_iterator<const TValue*>(&data[ARRAY_SIZE]);
+ }
+
+ //*****************************************************************************
+ /// Get the 'end' iterator for an array.
+ ///\ingroup container
+ //*****************************************************************************
+ template<typename TValue, const size_t ARRAY_SIZE>
+ TValue* end(TValue(&data)[ARRAY_SIZE])
+ {
+ return &data[ARRAY_SIZE];
+ }
+
+ //*****************************************************************************
+ /// Get the 'end' const iterator for an array.
+ ///\ingroup container
+ //*****************************************************************************
+ template<typename TValue, const size_t ARRAY_SIZE>
+ const TValue* end(const TValue(&data)[ARRAY_SIZE])
+ {
+ return &data[ARRAY_SIZE];
+ }
+
+ //*****************************************************************************
+ /// Get the 'end' const iterator for an array.
+ ///\ingroup container
+ //*****************************************************************************
+ template<typename TValue, const size_t ARRAY_SIZE>
+ const TValue* cend(const TValue(&data)[ARRAY_SIZE])
+ {
+ return &data[ARRAY_SIZE];
+ }
+
+ //*****************************************************************************
+ /// Get the 'end' reverse_iterator for an array.
+ ///\ingroup container
+ //*****************************************************************************
+ template<typename TValue, const size_t ARRAY_SIZE>
+ std::reverse_iterator<TValue*> rend(const TValue(&data)[ARRAY_SIZE])
+ {
+ return std::reverse_iterator<TValue*>(&data[0]);
+ }
+
+ //*****************************************************************************
+ /// Get the 'end' const reverse_iterator for an array.
+ ///\ingroup container
+ //*****************************************************************************
+ template<typename TValue, const size_t ARRAY_SIZE>
+ std::reverse_iterator<const TValue*> crend(const TValue(&data)[ARRAY_SIZE])
+ {
+ return std::reverse_iterator<const TValue*>(&data[0]);
+ }
+
+ //*****************************************************************************
+ /// Get the next iterator.
+ ///\ingroup container
+ //*****************************************************************************
+ template<class TIterator>
+ TIterator next(TIterator iterator, ptrdiff_t n = 1)
+ {
+ std::advance(iterator, n);
+ return iterator;
+ }
+
+ //*****************************************************************************
+ /// Get the previous iterator.
+ ///\ingroup container
+ //*****************************************************************************
+ template<class TIterator>
+ TIterator prev(TIterator iterator, ptrdiff_t n = 1)
+ {
+ std::advance(iterator, -n);
+ return iterator;
+ }
+
+ ///**************************************************************************
+ /// Get the size of a container.
+ /// Expects the container to have defined 'size_type'.
+ ///\ingroup container
+ ///**************************************************************************
+ template<typename TContainer>
+ typename TContainer::size_type size(const TContainer& container)
+ {
+ return container.size();
+ }
+
+ ///**************************************************************************
+ /// Get the size of an array in elements at run time.
+ ///\ingroup container
+ ///**************************************************************************
+ template<typename TValue, const size_t ARRAY_SIZE>
+ size_t size(TValue(&data)[ARRAY_SIZE])
+ {
+ return ARRAY_SIZE;
+ }
+
+ ///**************************************************************************
+ /// Get the size of an array in elements at compile time.
+ ///\code
+ /// sizeof(array_size(array))
+ ///\endcode
+ ///\ingroup container
+ ///**************************************************************************
+ template <typename T, const size_t ARRAY_SIZE>
+ char(&array_size(T(&array)[ARRAY_SIZE]))[ARRAY_SIZE];
+}
+
+#endif
+
diff --git a/lib/etl/crc16.cpp b/lib/etl/crc16.cpp
new file mode 100644
index 0000000..f519405
--- /dev/null
+++ b/lib/etl/crc16.cpp
@@ -0,0 +1,58 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#include <stdint.h>
+
+namespace etl
+{
+ //***************************************************************************
+ /// CRC16 table
+ /// \ingroup crc16
+ //***************************************************************************
+ extern const uint16_t CRC16[] =
+ {
+ 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
+ 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
+ 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
+ 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
+ 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
+ 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
+ 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
+ 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
+ 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
+ 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
+ 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
+ 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
+ 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
+ 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
+ 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
+ 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
+ };
+}
diff --git a/lib/etl/crc16.h b/lib/etl/crc16.h
new file mode 100644
index 0000000..18dc88e
--- /dev/null
+++ b/lib/etl/crc16.h
@@ -0,0 +1,108 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_CRC16__
+#define __ETL_CRC16__
+
+#include <stdint.h>
+#include <iterator>
+
+#include "platform.h"
+#include "frame_check_sequence.h"
+
+#if defined(ETL_COMPILER_KEIL)
+#pragma diag_suppress 1300
+#endif
+
+///\defgroup crc16 16 bit CRC calculation
+///\ingroup crc
+
+namespace etl
+{
+ //***************************************************************************
+ /// CRC16 table
+ /// \ingroup crc16
+ //***************************************************************************
+ extern const uint16_t CRC16[];
+
+ //***************************************************************************
+ /// CRC16 policy.
+ /// Calculates CRC16 using polynomial 0x8005.
+ //***************************************************************************
+ struct crc_policy_16
+ {
+ typedef uint16_t value_type;
+
+ inline uint16_t initial() const
+ {
+ return 0;
+ }
+
+ inline uint16_t add(uint16_t crc, uint8_t value) const
+ {
+ return (crc >> 8) ^ CRC16[(crc ^ value) & 0xFF];
+ }
+
+ inline uint16_t final(uint16_t crc) const
+ {
+ return crc;
+ }
+ };
+
+ //*************************************************************************
+ /// CRC16
+ //*************************************************************************
+ class crc16 : public etl::frame_check_sequence<etl::crc_policy_16>
+ {
+ public:
+
+ //*************************************************************************
+ /// Default constructor.
+ //*************************************************************************
+ crc16()
+ {
+ this->reset();
+ }
+
+ //*************************************************************************
+ /// Constructor from range.
+ /// \param begin Start of the range.
+ /// \param end End of the range.
+ //*************************************************************************
+ template<typename TIterator>
+ crc16(TIterator begin, const TIterator end)
+ {
+ this->reset();
+ this->add(begin, end);
+ }
+ };
+}
+
+#endif
diff --git a/lib/etl/crc16_ccitt.cpp b/lib/etl/crc16_ccitt.cpp
new file mode 100644
index 0000000..6c800d7
--- /dev/null
+++ b/lib/etl/crc16_ccitt.cpp
@@ -0,0 +1,58 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#include <stdint.h>
+
+namespace etl
+{
+ //***************************************************************************
+ /// CRC-CCITT table
+ /// \ingroup crc16_ccitt
+ //***************************************************************************
+ extern const uint16_t CRC_CCITT[] =
+ {
+ 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
+ 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
+ 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
+ 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
+ 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
+ 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
+ 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
+ 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
+ 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
+ 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
+ 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+ 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
+ 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
+ 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
+ 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
+ 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
+ };
+}
diff --git a/lib/etl/crc16_ccitt.h b/lib/etl/crc16_ccitt.h
new file mode 100644
index 0000000..3cedd82
--- /dev/null
+++ b/lib/etl/crc16_ccitt.h
@@ -0,0 +1,108 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_CRC16_CCITT__
+#define __ETL_CRC16_CCITT__
+
+#include <stdint.h>
+#include <iterator>
+
+#include "platform.h"
+#include "frame_check_sequence.h"
+
+#if defined(ETL_COMPILER_KEIL)
+#pragma diag_suppress 1300
+#endif
+
+///\defgroup crc16_ccitt 16 bit CRC CCITT calculation
+///\ingroup crc
+
+namespace etl
+{
+ //***************************************************************************
+ /// CRC-CCITT table
+ /// \ingroup crc16_ccitt
+ //***************************************************************************
+ extern const uint16_t CRC_CCITT[];
+
+ //***************************************************************************
+ /// CRC16 CCITT policy.
+ /// Calculates CRC16 CCITT using polynomial 0x1021
+ //***************************************************************************
+ struct crc_policy_16_ccitt
+ {
+ typedef uint16_t value_type;
+
+ inline uint16_t initial() const
+ {
+ return 0xFFFF;
+ }
+
+ inline uint16_t add(uint16_t crc, uint8_t value) const
+ {
+ return (crc << 8) ^ CRC_CCITT[((crc >> 8) ^ value) & 0xFF];
+ }
+
+ inline uint16_t final(uint16_t crc) const
+ {
+ return crc;
+ }
+ };
+
+ //*************************************************************************
+ /// CRC16 CCITT
+ //*************************************************************************
+ class crc16_ccitt : public etl::frame_check_sequence<etl::crc_policy_16_ccitt>
+ {
+ public:
+
+ //*************************************************************************
+ /// Default constructor.
+ //*************************************************************************
+ crc16_ccitt()
+ {
+ this->reset();
+ }
+
+ //*************************************************************************
+ /// Constructor from range.
+ /// \param begin Start of the range.
+ /// \param end End of the range.
+ //*************************************************************************
+ template<typename TIterator>
+ crc16_ccitt(TIterator begin, const TIterator end)
+ {
+ this->reset();
+ this->add(begin, end);
+ }
+ };
+}
+
+#endif
diff --git a/lib/etl/crc16_kermit.cpp b/lib/etl/crc16_kermit.cpp
new file mode 100644
index 0000000..c7363d1
--- /dev/null
+++ b/lib/etl/crc16_kermit.cpp
@@ -0,0 +1,58 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#include <stdint.h>
+
+namespace etl
+{
+ //***************************************************************************
+ /// CRC Kermit table
+ /// \ingroup crc16_kermit
+ //***************************************************************************
+ extern const uint16_t CRC_KERMIT[] =
+ {
+ 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF, 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
+ 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E, 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
+ 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD, 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
+ 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C, 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
+ 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB, 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
+ 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A, 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
+ 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9, 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
+ 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738, 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
+ 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7, 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
+ 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036, 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
+ 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5, 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
+ 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134, 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
+ 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3, 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
+ 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232, 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
+ 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1, 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
+ 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330, 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
+ };
+}
diff --git a/lib/etl/crc16_kermit.h b/lib/etl/crc16_kermit.h
new file mode 100644
index 0000000..146b850
--- /dev/null
+++ b/lib/etl/crc16_kermit.h
@@ -0,0 +1,108 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_CRC16_KERMIT__
+#define __ETL_CRC16_KERMIT__
+
+#include <stdint.h>
+#include <iterator>
+
+#include "platform.h"
+#include "frame_check_sequence.h"
+
+#if defined(ETL_COMPILER_KEIL)
+#pragma diag_suppress 1300
+#endif
+
+///\defgroup crc16_kermit 16 bit CRC Kermit calculation
+///\ingroup crc
+
+namespace etl
+{
+ //***************************************************************************
+ /// CRC Kermit table
+ /// \ingroup crc
+ //***************************************************************************
+ extern const uint16_t CRC_KERMIT[];
+
+ //***************************************************************************
+ /// CRC16 Kermit policy.
+ /// Calculates CRC16 Kermit using polynomial 0x1021
+ //***************************************************************************
+ struct crc_policy_16_kermit
+ {
+ typedef uint16_t value_type;
+
+ inline uint16_t initial() const
+ {
+ return 0;
+ }
+
+ inline uint16_t add(uint16_t crc, uint8_t value) const
+ {
+ return (crc >> 8) ^ CRC_KERMIT[(crc ^ value) & 0xFF];
+ }
+
+ inline uint16_t final(uint16_t crc) const
+ {
+ return crc;
+ }
+ };
+
+ //*************************************************************************
+ /// CRC16 Kermit
+ //*************************************************************************
+ class crc16_kermit : public etl::frame_check_sequence<etl::crc_policy_16_kermit>
+ {
+ public:
+
+ //*************************************************************************
+ /// Default constructor.
+ //*************************************************************************
+ crc16_kermit()
+ {
+ this->reset();
+ }
+
+ //*************************************************************************
+ /// Constructor from range.
+ /// \param begin Start of the range.
+ /// \param end End of the range.
+ //*************************************************************************
+ template<typename TIterator>
+ crc16_kermit(TIterator begin, const TIterator end)
+ {
+ this->reset();
+ this->add(begin, end);
+ }
+ };
+}
+
+#endif
diff --git a/lib/etl/crc32.cpp b/lib/etl/crc32.cpp
new file mode 100644
index 0000000..9b7c0be
--- /dev/null
+++ b/lib/etl/crc32.cpp
@@ -0,0 +1,74 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#include <stdint.h>
+
+namespace etl
+{
+ //***************************************************************************
+ /// CRC32 table
+ /// \ingroup crc32
+ //***************************************************************************
+ extern const uint32_t CRC32[] =
+ {
+ 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
+ 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
+ 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
+ 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
+ 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
+ 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
+ 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
+ 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
+ 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
+ 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
+ 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
+ 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
+ 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
+ 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
+ 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
+ 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
+ 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
+ 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
+ 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
+ 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
+ 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
+ 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
+ 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
+ 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
+ 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
+ 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
+ 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
+ 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
+ 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
+ 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
+ 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
+ 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
+ };
+}
diff --git a/lib/etl/crc32.h b/lib/etl/crc32.h
new file mode 100644
index 0000000..477fdfa
--- /dev/null
+++ b/lib/etl/crc32.h
@@ -0,0 +1,108 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_CRC32__
+#define __ETL_CRC32__
+
+#include <stdint.h>
+#include <iterator>
+
+#include "platform.h"
+#include "frame_check_sequence.h"
+
+#if defined(ETL_COMPILER_KEIL)
+#pragma diag_suppress 1300
+#endif
+
+///\defgroup crc32 32 bit CRC calculation
+///\ingroup crc
+
+namespace etl
+{
+ //***************************************************************************
+ /// CRC32 table
+ /// \ingroup crc32
+ //***************************************************************************
+ extern const uint32_t CRC32[];
+
+ //***************************************************************************
+ /// CRC32 policy.
+ /// Calculates CRC32 using polynomial 0x04C11DB7.
+ //***************************************************************************
+ struct crc_policy_32
+ {
+ typedef uint32_t value_type;
+
+ inline uint32_t initial() const
+ {
+ return 0xFFFFFFFF;
+ }
+
+ inline uint32_t add(uint32_t crc, uint8_t value) const
+ {
+ return (crc >> 8) ^ CRC32[(crc ^ value) & 0xFF];
+ }
+
+ inline uint32_t final(uint32_t crc) const
+ {
+ return crc ^ 0xFFFFFFFF;
+ }
+ };
+
+ //*************************************************************************
+ /// CRC32
+ //*************************************************************************
+ class crc32 : public etl::frame_check_sequence<etl::crc_policy_32>
+ {
+ public:
+
+ //*************************************************************************
+ /// Default constructor.
+ //*************************************************************************
+ crc32()
+ {
+ this->reset();
+ }
+
+ //*************************************************************************
+ /// Constructor from range.
+ /// \param begin Start of the range.
+ /// \param end End of the range.
+ //*************************************************************************
+ template<typename TIterator>
+ crc32(TIterator begin, const TIterator end)
+ {
+ this->reset();
+ this->add(begin, end);
+ }
+ };
+}
+
+#endif
diff --git a/lib/etl/crc64_ecma.cpp b/lib/etl/crc64_ecma.cpp
new file mode 100644
index 0000000..7b41a3d
--- /dev/null
+++ b/lib/etl/crc64_ecma.cpp
@@ -0,0 +1,106 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#include <stdint.h>
+
+namespace etl
+{
+ //***************************************************************************
+ /// CRC64_ECMA table
+ /// \ingroup crc64_ecma
+ //***************************************************************************
+ extern const uint64_t CRC64_ECMA[] =
+ {
+ 0x0000000000000000, 0x42F0E1EBA9EA3693, 0x85E1C3D753D46D26, 0xC711223CFA3E5BB5,
+ 0x493366450E42ECDF, 0x0BC387AEA7A8DA4C, 0xCCD2A5925D9681F9, 0x8E224479F47CB76A,
+ 0x9266CC8A1C85D9BE, 0xD0962D61B56FEF2D, 0x17870F5D4F51B498, 0x5577EEB6E6BB820B,
+ 0xDB55AACF12C73561, 0x99A54B24BB2D03F2, 0x5EB4691841135847, 0x1C4488F3E8F96ED4,
+ 0x663D78FF90E185EF, 0x24CD9914390BB37C, 0xE3DCBB28C335E8C9, 0xA12C5AC36ADFDE5A,
+ 0x2F0E1EBA9EA36930, 0x6DFEFF5137495FA3, 0xAAEFDD6DCD770416, 0xE81F3C86649D3285,
+ 0xF45BB4758C645C51, 0xB6AB559E258E6AC2, 0x71BA77A2DFB03177, 0x334A9649765A07E4,
+ 0xBD68D2308226B08E, 0xFF9833DB2BCC861D, 0x388911E7D1F2DDA8, 0x7A79F00C7818EB3B,
+ 0xCC7AF1FF21C30BDE, 0x8E8A101488293D4D, 0x499B3228721766F8, 0x0B6BD3C3DBFD506B,
+ 0x854997BA2F81E701, 0xC7B97651866BD192, 0x00A8546D7C558A27, 0x4258B586D5BFBCB4,
+ 0x5E1C3D753D46D260, 0x1CECDC9E94ACE4F3, 0xDBFDFEA26E92BF46, 0x990D1F49C77889D5,
+ 0x172F5B3033043EBF, 0x55DFBADB9AEE082C, 0x92CE98E760D05399, 0xD03E790CC93A650A,
+ 0xAA478900B1228E31, 0xE8B768EB18C8B8A2, 0x2FA64AD7E2F6E317, 0x6D56AB3C4B1CD584,
+ 0xE374EF45BF6062EE, 0xA1840EAE168A547D, 0x66952C92ECB40FC8, 0x2465CD79455E395B,
+ 0x3821458AADA7578F, 0x7AD1A461044D611C, 0xBDC0865DFE733AA9, 0xFF3067B657990C3A,
+ 0x711223CFA3E5BB50, 0x33E2C2240A0F8DC3, 0xF4F3E018F031D676, 0xB60301F359DBE0E5,
+ 0xDA050215EA6C212F, 0x98F5E3FE438617BC, 0x5FE4C1C2B9B84C09, 0x1D14202910527A9A,
+ 0x93366450E42ECDF0, 0xD1C685BB4DC4FB63, 0x16D7A787B7FAA0D6, 0x5427466C1E109645,
+ 0x4863CE9FF6E9F891, 0x0A932F745F03CE02, 0xCD820D48A53D95B7, 0x8F72ECA30CD7A324,
+ 0x0150A8DAF8AB144E, 0x43A04931514122DD, 0x84B16B0DAB7F7968, 0xC6418AE602954FFB,
+ 0xBC387AEA7A8DA4C0, 0xFEC89B01D3679253, 0x39D9B93D2959C9E6, 0x7B2958D680B3FF75,
+ 0xF50B1CAF74CF481F, 0xB7FBFD44DD257E8C, 0x70EADF78271B2539, 0x321A3E938EF113AA,
+ 0x2E5EB66066087D7E, 0x6CAE578BCFE24BED, 0xABBF75B735DC1058, 0xE94F945C9C3626CB,
+ 0x676DD025684A91A1, 0x259D31CEC1A0A732, 0xE28C13F23B9EFC87, 0xA07CF2199274CA14,
+ 0x167FF3EACBAF2AF1, 0x548F120162451C62, 0x939E303D987B47D7, 0xD16ED1D631917144,
+ 0x5F4C95AFC5EDC62E, 0x1DBC74446C07F0BD, 0xDAAD56789639AB08, 0x985DB7933FD39D9B,
+ 0x84193F60D72AF34F, 0xC6E9DE8B7EC0C5DC, 0x01F8FCB784FE9E69, 0x43081D5C2D14A8FA,
+ 0xCD2A5925D9681F90, 0x8FDAB8CE70822903, 0x48CB9AF28ABC72B6, 0x0A3B7B1923564425,
+ 0x70428B155B4EAF1E, 0x32B26AFEF2A4998D, 0xF5A348C2089AC238, 0xB753A929A170F4AB,
+ 0x3971ED50550C43C1, 0x7B810CBBFCE67552, 0xBC902E8706D82EE7, 0xFE60CF6CAF321874,
+ 0xE224479F47CB76A0, 0xA0D4A674EE214033, 0x67C58448141F1B86, 0x253565A3BDF52D15,
+ 0xAB1721DA49899A7F, 0xE9E7C031E063ACEC, 0x2EF6E20D1A5DF759, 0x6C0603E6B3B7C1CA,
+ 0xF6FAE5C07D3274CD, 0xB40A042BD4D8425E, 0x731B26172EE619EB, 0x31EBC7FC870C2F78,
+ 0xBFC9838573709812, 0xFD39626EDA9AAE81, 0x3A28405220A4F534, 0x78D8A1B9894EC3A7,
+ 0x649C294A61B7AD73, 0x266CC8A1C85D9BE0, 0xE17DEA9D3263C055, 0xA38D0B769B89F6C6,
+ 0x2DAF4F0F6FF541AC, 0x6F5FAEE4C61F773F, 0xA84E8CD83C212C8A, 0xEABE6D3395CB1A19,
+ 0x90C79D3FEDD3F122, 0xD2377CD44439C7B1, 0x15265EE8BE079C04, 0x57D6BF0317EDAA97,
+ 0xD9F4FB7AE3911DFD, 0x9B041A914A7B2B6E, 0x5C1538ADB04570DB, 0x1EE5D94619AF4648,
+ 0x02A151B5F156289C, 0x4051B05E58BC1E0F, 0x87409262A28245BA, 0xC5B073890B687329,
+ 0x4B9237F0FF14C443, 0x0962D61B56FEF2D0, 0xCE73F427ACC0A965, 0x8C8315CC052A9FF6,
+ 0x3A80143F5CF17F13, 0x7870F5D4F51B4980, 0xBF61D7E80F251235, 0xFD913603A6CF24A6,
+ 0x73B3727A52B393CC, 0x31439391FB59A55F, 0xF652B1AD0167FEEA, 0xB4A25046A88DC879,
+ 0xA8E6D8B54074A6AD, 0xEA16395EE99E903E, 0x2D071B6213A0CB8B, 0x6FF7FA89BA4AFD18,
+ 0xE1D5BEF04E364A72, 0xA3255F1BE7DC7CE1, 0x64347D271DE22754, 0x26C49CCCB40811C7,
+ 0x5CBD6CC0CC10FAFC, 0x1E4D8D2B65FACC6F, 0xD95CAF179FC497DA, 0x9BAC4EFC362EA149,
+ 0x158E0A85C2521623, 0x577EEB6E6BB820B0, 0x906FC95291867B05, 0xD29F28B9386C4D96,
+ 0xCEDBA04AD0952342, 0x8C2B41A1797F15D1, 0x4B3A639D83414E64, 0x09CA82762AAB78F7,
+ 0x87E8C60FDED7CF9D, 0xC51827E4773DF90E, 0x020905D88D03A2BB, 0x40F9E43324E99428,
+ 0x2CFFE7D5975E55E2, 0x6E0F063E3EB46371, 0xA91E2402C48A38C4, 0xEBEEC5E96D600E57,
+ 0x65CC8190991CB93D, 0x273C607B30F68FAE, 0xE02D4247CAC8D41B, 0xA2DDA3AC6322E288,
+ 0xBE992B5F8BDB8C5C, 0xFC69CAB42231BACF, 0x3B78E888D80FE17A, 0x7988096371E5D7E9,
+ 0xF7AA4D1A85996083, 0xB55AACF12C735610, 0x724B8ECDD64D0DA5, 0x30BB6F267FA73B36,
+ 0x4AC29F2A07BFD00D, 0x08327EC1AE55E69E, 0xCF235CFD546BBD2B, 0x8DD3BD16FD818BB8,
+ 0x03F1F96F09FD3CD2, 0x41011884A0170A41, 0x86103AB85A2951F4, 0xC4E0DB53F3C36767,
+ 0xD8A453A01B3A09B3, 0x9A54B24BB2D03F20, 0x5D45907748EE6495, 0x1FB5719CE1045206,
+ 0x919735E51578E56C, 0xD367D40EBC92D3FF, 0x1476F63246AC884A, 0x568617D9EF46BED9,
+ 0xE085162AB69D5E3C, 0xA275F7C11F7768AF, 0x6564D5FDE549331A, 0x279434164CA30589,
+ 0xA9B6706FB8DFB2E3, 0xEB46918411358470, 0x2C57B3B8EB0BDFC5, 0x6EA7525342E1E956,
+ 0x72E3DAA0AA188782, 0x30133B4B03F2B111, 0xF7021977F9CCEAA4, 0xB5F2F89C5026DC37,
+ 0x3BD0BCE5A45A6B5D, 0x79205D0E0DB05DCE, 0xBE317F32F78E067B, 0xFCC19ED95E6430E8,
+ 0x86B86ED5267CDBD3, 0xC4488F3E8F96ED40, 0x0359AD0275A8B6F5, 0x41A94CE9DC428066,
+ 0xCF8B0890283E370C, 0x8D7BE97B81D4019F, 0x4A6ACB477BEA5A2A, 0x089A2AACD2006CB9,
+ 0x14DEA25F3AF9026D, 0x562E43B4931334FE, 0x913F6188692D6F4B, 0xD3CF8063C0C759D8,
+ 0x5DEDC41A34BBEEB2, 0x1F1D25F19D51D821, 0xD80C07CD676F8394, 0x9AFCE626CE85B507
+ };
+}
diff --git a/lib/etl/crc64_ecma.h b/lib/etl/crc64_ecma.h
new file mode 100644
index 0000000..c098d61
--- /dev/null
+++ b/lib/etl/crc64_ecma.h
@@ -0,0 +1,108 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_CRC64_ECMA__
+#define __ETL_CRC64_ECMA__
+
+#include <stdint.h>
+#include <iterator>
+
+#include "platform.h"
+#include "frame_check_sequence.h"
+
+#if defined(ETL_COMPILER_KEIL)
+#pragma diag_suppress 1300
+#endif
+
+///\defgroup crc64_ecma 64 bit CRC ECMA calculation
+///\ingroup crc
+
+namespace etl
+{
+ //***************************************************************************
+ /// CRC64_ECMA table
+ /// \ingroup crc64_ecma
+ //***************************************************************************
+ extern const uint64_t CRC64_ECMA[];
+
+ //***************************************************************************
+ /// CRC64 policy.
+ /// Calculates CRC64 ECMA using polynomial 0x42F0E1EBA9EA3693.
+ //***************************************************************************
+ struct crc_policy_64_ecma
+ {
+ typedef uint64_t value_type;
+
+ inline uint64_t initial() const
+ {
+ return 0;
+ }
+
+ inline uint64_t add(uint64_t crc, uint8_t value) const
+ {
+ return (crc << 8) ^ CRC64_ECMA[((crc >> 56) ^ value) & 0xFF];
+ }
+
+ inline uint64_t final(uint64_t crc) const
+ {
+ return crc;
+ }
+ };
+
+ //*************************************************************************
+ /// CRC64 ECMA
+ //*************************************************************************
+ class crc64_ecma : public etl::frame_check_sequence<etl::crc_policy_64_ecma>
+ {
+ public:
+
+ //*************************************************************************
+ /// Default constructor.
+ //*************************************************************************
+ crc64_ecma()
+ {
+ this->reset();
+ }
+
+ //*************************************************************************
+ /// Constructor from range.
+ /// \param begin Start of the range.
+ /// \param end End of the range.
+ //*************************************************************************
+ template<typename TIterator>
+ crc64_ecma(TIterator begin, const TIterator end)
+ {
+ this->reset();
+ this->add(begin, end);
+ }
+ };
+}
+
+#endif
diff --git a/lib/etl/crc8_ccitt.cpp b/lib/etl/crc8_ccitt.cpp
new file mode 100644
index 0000000..1919d21
--- /dev/null
+++ b/lib/etl/crc8_ccitt.cpp
@@ -0,0 +1,58 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#include <stdint.h>
+
+namespace etl
+{
+ //***************************************************************************
+ /// CRC8 table
+ /// \ingroup crc8_ccitt
+ //***************************************************************************
+ extern const uint8_t CRC8_CCITT[] =
+ {
+ 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
+ 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
+ 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
+ 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
+ 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
+ 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
+ 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
+ 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
+ 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
+ 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
+ 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
+ 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
+ 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
+ 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
+ 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
+ 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3
+ };
+}
diff --git a/lib/etl/crc8_ccitt.h b/lib/etl/crc8_ccitt.h
new file mode 100644
index 0000000..112b294
--- /dev/null
+++ b/lib/etl/crc8_ccitt.h
@@ -0,0 +1,108 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_CRC8_CCITT__
+#define __ETL_CRC8_CCITT__
+
+#include <stdint.h>
+#include <iterator>
+
+#include "platform.h"
+#include "frame_check_sequence.h"
+
+#if defined(ETL_COMPILER_KEIL)
+#pragma diag_suppress 1300
+#endif
+
+///\defgroup crc8_ccitt 8 bit CRC calculation
+///\ingroup crc
+
+namespace etl
+{
+ //***************************************************************************
+ /// CRC8 table
+ /// \ingroup crc8_ccitt
+ //***************************************************************************
+ extern const uint8_t CRC8_CCITT[];
+
+ //***************************************************************************
+ /// CRC8 CCITT policy.
+ /// Calculates CRC8 CCITT using polynomial 0x07.
+ //***************************************************************************
+ struct crc_policy_8_ccitt
+ {
+ typedef uint8_t value_type;
+
+ inline uint8_t initial() const
+ {
+ return 0;
+ }
+
+ inline uint8_t add(uint8_t crc, uint8_t value) const
+ {
+ return CRC8_CCITT[crc ^ value];
+ }
+
+ inline uint8_t final(uint8_t crc) const
+ {
+ return crc;
+ }
+ };
+
+ //*************************************************************************
+ /// CRC8 CCITT
+ //*************************************************************************
+ class crc8_ccitt : public etl::frame_check_sequence<etl::crc_policy_8_ccitt>
+ {
+ public:
+
+ //*************************************************************************
+ /// Default constructor.
+ //*************************************************************************
+ crc8_ccitt()
+ {
+ this->reset();
+ }
+
+ //*************************************************************************
+ /// Constructor from range.
+ /// \param begin Start of the range.
+ /// \param end End of the range.
+ //*************************************************************************
+ template<typename TIterator>
+ crc8_ccitt(TIterator begin, const TIterator end)
+ {
+ this->reset();
+ this->add(begin, end);
+ }
+ };
+}
+
+#endif
diff --git a/lib/etl/cyclic_value.h b/lib/etl/cyclic_value.h
new file mode 100644
index 0000000..6ed18c7
--- /dev/null
+++ b/lib/etl/cyclic_value.h
@@ -0,0 +1,300 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_CYCLIC_VALUE__
+#define __ETL_CYCLIC_VALUE__
+
+#include <stddef.h>
+
+///\defgroup cyclic_value cyclic_value
+/// Provides a value that cycles between two limits.
+/// \ingroup utilities
+
+#include <algorithm>
+
+#include "static_assert.h"
+#include "exception.h"
+
+namespace etl
+{
+ //***************************************************************************
+ /// Provides a value that cycles between two limits.
+ /// Supports incrementing and decrementing.
+ ///\tparam T The type of the variable.
+ ///\tparam FIRST The first value of the range.
+ ///\tparam LAST The last value of the range.
+ ///\ingroup cyclic_value
+ //***************************************************************************
+ template <typename T, const T FIRST = T(), const T LAST = T()>
+ class cyclic_value
+ {
+ public:
+
+ template <typename U, const U OTHER_FIRST, const U OTHER_LAST> friend class cyclic_value;
+
+ //*************************************************************************
+ /// Constructor.
+ /// Sets 'first' and 'last' to the template parameter values.
+ /// The initial value is set to the first value.
+ //*************************************************************************
+ cyclic_value()
+ : value(FIRST),
+ first_value(FIRST),
+ last_value(LAST)
+ {
+ }
+
+ //*************************************************************************
+ /// Constructor.
+ /// Sets the value to the first of the range.
+ ///\param first The first value in the range.
+ ///\param last The last value in the range.
+ //*************************************************************************
+ cyclic_value(const T& first_, const T& last_)
+ : value(first_),
+ first_value(first_),
+ last_value(last_)
+ {
+ }
+
+ //*************************************************************************
+ /// Sets the range.
+ /// Sets the value to the first of the range.
+ ///\param first The first value in the range.
+ ///\param last The last value in the range.
+ //*************************************************************************
+ void set(const T& first_, const T& last_)
+ {
+ first_value = first_;
+ last_value = last_;
+ value = first_;
+ }
+
+ //*************************************************************************
+ /// Resets the value to the first in the range.
+ //*************************************************************************
+ void to_first()
+ {
+ value = first_value;
+ }
+
+ //*************************************************************************
+ /// Resets the value to the last in the range.
+ //*************************************************************************
+ void to_last()
+ {
+ value = last_value;
+ }
+
+ //*************************************************************************
+ /// Advances to value by a number of steps.
+ ///\param n The number of steps to advance.
+ //*************************************************************************
+ void advance(int n)
+ {
+ if (n > 0)
+ {
+ for (int i = 0; i < n; ++i)
+ {
+ operator ++();
+ }
+ }
+ else
+ {
+ for (int i = 0; i < -n; ++i)
+ {
+ operator --();
+ }
+ }
+ }
+
+ //*************************************************************************
+ /// Conversion operator.
+ /// \return The value of the underlying type.
+ //*************************************************************************
+ operator T()
+ {
+ return value;
+ }
+
+ //*************************************************************************
+ /// Const conversion operator.
+ /// \return The value of the underlying type.
+ //*************************************************************************
+ operator const T() const
+ {
+ return value;
+ }
+
+ //*************************************************************************
+ /// ++ operator.
+ //*************************************************************************
+ cyclic_value& operator ++()
+ {
+ if (value == last_value)
+ {
+ value = first_value;
+ }
+ else
+ {
+ ++value;
+ }
+
+ return *this;
+ }
+
+ //*************************************************************************
+ /// ++ operator.
+ //*************************************************************************
+ cyclic_value operator ++(int)
+ {
+ cyclic_value temp(*this);
+
+ operator++();
+
+ return temp;
+ }
+
+ //*************************************************************************
+ /// -- operator.
+ //*************************************************************************
+ cyclic_value& operator --()
+ {
+ if (value == first_value)
+ {
+ value = last_value;
+ }
+ else
+ {
+ --value;
+ }
+
+ return *this;
+ }
+
+ //*************************************************************************
+ /// -- operator.
+ //*************************************************************************
+ cyclic_value operator --(int)
+ {
+ cyclic_value temp(*this);
+
+ operator--();
+
+ return temp;
+ }
+
+ //*************************************************************************
+ /// = operator.
+ //*************************************************************************
+ cyclic_value& operator =(T t)
+ {
+ value = t;
+ return *this;
+ }
+
+ //*************************************************************************
+ /// = operator.
+ //*************************************************************************
+ template <const T OTHER_FIRST, const T OTHER_LAST>
+ cyclic_value& operator =(const cyclic_value<T, OTHER_FIRST, OTHER_LAST>& other)
+ {
+ value = other.value;
+ first_value = other.first_value;
+ last_value = other.last_value;
+ return *this;
+ }
+
+ //*************************************************************************
+ /// Gets the first value.
+ //*************************************************************************
+ const T& first() const
+ {
+ return first_value;
+ }
+
+ //*************************************************************************
+ /// Gets the last value.
+ //*************************************************************************
+ const T& last() const
+ {
+ return last_value;
+ }
+
+ //*************************************************************************
+ /// Swaps the values.
+ //*************************************************************************
+ template <const T OTHER_FIRST, const T OTHER_LAST>
+ void swap(cyclic_value<T, OTHER_FIRST, OTHER_LAST>& other)
+ {
+ std::swap(first_value, other.first_value);
+ std::swap(last_value, other.last_value);
+ std::swap(value, other.value);
+ }
+
+ private:
+
+ T value; ///< The current value.
+ T first_value; ///< The first value in the range.
+ T last_value; ///< The last value in the range.
+ };
+
+ //*************************************************************************
+ /// Swaps the values.
+ //*************************************************************************
+ template <typename T, const T LHS_FIRST, const T LHS_LAST, const T RHS_FIRST, const T RHS_LAST>
+ void swap(cyclic_value<T, LHS_FIRST, LHS_LAST>& lhs,
+ cyclic_value<T, RHS_FIRST, RHS_LAST>& rhs)
+ {
+ lhs.swap(rhs);
+ }
+
+ //*************************************************************************
+ /// Equality operator.
+ //*************************************************************************
+ template <typename T, const T LHS_FIRST, const T LHS_LAST, const T RHS_FIRST, const T RHS_LAST>
+ bool operator == (const cyclic_value<T, LHS_FIRST, LHS_LAST>& lhs,
+ const cyclic_value<T, RHS_FIRST, RHS_LAST>& rhs)
+ {
+ return static_cast<T>(lhs) == static_cast<T>(rhs);
+ }
+
+ //*************************************************************************
+ /// Inequality operator.
+ //*************************************************************************
+ template <typename T, const T LHS_FIRST, const T LHS_LAST, const T RHS_FIRST, const T RHS_LAST>
+ bool operator != (const cyclic_value<T, LHS_FIRST, RHS_LAST>& lhs,
+ const cyclic_value<T, RHS_FIRST, RHS_LAST>& rhs)
+ {
+ return !(lhs == rhs);
+ }
+}
+
+#endif
diff --git a/lib/etl/debounce.h b/lib/etl/debounce.h
new file mode 100644
index 0000000..531b584
--- /dev/null
+++ b/lib/etl/debounce.h
@@ -0,0 +1,488 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_DEBOUNCE__
+#define __ETL_DEBOUNCE__
+
+#include <stdint.h>
+
+#include "static_assert.h"
+
+namespace etl
+{
+ namespace __private_debounce__
+ {
+ class debounce_base
+ {
+ public:
+
+ void add(bool sample)
+ {
+ state &= ~CHANGED;
+
+ // Changed from last time?
+ if (sample != bool((state & LAST) != 0))
+ {
+ count = START_COUNT;
+ }
+ }
+
+ //*************************************************************************
+ /// Gets the current debouncer change state.
+ ///\return 'true' if the debouncer has changed state.
+ //*************************************************************************
+ bool has_changed() const
+ {
+ return (state & CHANGED) != 0;
+ }
+
+ //*************************************************************************
+ /// Gets the current debouncer state.
+ ///\return 'true' if the debouncer is in the true state.
+ //*************************************************************************
+ bool is_set() const
+ {
+ return (state & CURRENT) != 0;
+ }
+
+ //*************************************************************************
+ /// Gets the debouncer hold state.
+ ///\return 'true' if the debouncer is in the hold state.
+ //*************************************************************************
+ bool is_held() const
+ {
+ return (state & HELD) != 0;
+ }
+
+ //*************************************************************************
+ /// Gets the debouncer repeat state.
+ ///\return 'true' if the debouncer is repeating.
+ //*************************************************************************
+ bool is_repeating() const
+ {
+ return (state & REPEATING) != 0;
+ }
+
+ protected:
+
+ //*************************************************************************
+ /// Constructor.
+ ///\param initial_state The initial state. Default = false.
+ //*************************************************************************
+ debounce_base(bool initial_state = false)
+ : state(initial_state ? (CURRENT | LAST) : 0),
+ count(START_COUNT)
+ {
+ }
+
+ enum
+ {
+ START_COUNT = 0
+ };
+
+ enum
+ {
+ CURRENT = 1,
+ LAST = 2,
+ HELD = 4,
+ CHANGED = 8,
+ REPEATING = 16
+ };
+
+ uint8_t state;
+
+ /// The state count.
+ uint16_t count;
+ };
+ }
+
+ //***************************************************************************
+ /// A class to debounce signals.
+ /// The state is decided over N samples, defined by the VALID_COUNT value.
+ /// If the samples are consistent for VALID_COUNT times then the debouncer state is defined.
+ /// If the samples change then the debouncer will change state after VALID_COUNT samples.
+ /// If the samples are true for a count of HOLD_COUNT then the debouncer input is 'held'.
+ /// The debouncer may be constructed in either state.
+ //***************************************************************************
+ template <const uint16_t VALID_COUNT = 0, const uint16_t HOLD_COUNT = 0, const uint16_t REPEAT_COUNT = 0>
+ class debounce : public __private_debounce__::debounce_base
+ {
+ private:
+
+ enum
+ {
+ VALID_THRESHOLD = VALID_COUNT,
+ HOLD_THRESHOLD = VALID_THRESHOLD + HOLD_COUNT,
+ REPEAT_THRESHOLD = HOLD_THRESHOLD + REPEAT_COUNT
+ };
+
+ using debounce_base::add;
+
+ public:
+
+ //*************************************************************************
+ /// Constructor.
+ ///\param initial_state The initial state. Default = false.
+ //*************************************************************************
+ debounce(bool initial_state = false)
+ : debounce_base(initial_state)
+ {
+ }
+
+ //*************************************************************************
+ /// Adds a new sample.
+ /// Returns 'true' if the debouncer changes state from...
+ /// 1. Clear to Set.
+ /// 2. Set to Clear.
+ /// 3. Not Held to Held.
+ /// 4. Key repeats.
+ ///\param sample The new sample.
+ ///\return 'true' if the debouncer changed state.
+ //*************************************************************************
+ bool add(bool sample)
+ {
+ debounce_base::add(sample);
+
+ if (count < REPEAT_THRESHOLD)
+ {
+ ++count;
+
+ if (sample)
+ {
+ if (count == VALID_THRESHOLD)
+ {
+ // Set.
+ state |= CHANGED;
+ state |= CURRENT;
+ }
+ else if (count == HOLD_THRESHOLD)
+ {
+ // Held.
+ state |= CHANGED;
+ state |= HELD;
+ }
+ else if (count == REPEAT_THRESHOLD)
+ {
+ // Repeat.
+ state |= CHANGED;
+ state |= REPEATING;
+ count = HOLD_THRESHOLD;
+ }
+
+ state |= LAST;
+ }
+ else
+ {
+ if (count == VALID_THRESHOLD)
+ {
+ // Clear.
+ state |= CHANGED;
+ state &= ~CURRENT;
+ state &= ~HELD;
+ state &= ~REPEATING;
+ }
+
+ state &= ~LAST;
+ }
+ }
+
+ return (state & CHANGED) != 0;
+ }
+ };
+
+ template <const uint16_t VALID_COUNT, const uint16_t HOLD_COUNT>
+ class debounce<VALID_COUNT, HOLD_COUNT, 0> : public __private_debounce__::debounce_base
+ {
+ private:
+
+ enum
+ {
+ VALID_THRESHOLD = VALID_COUNT,
+ HOLD_THRESHOLD = VALID_THRESHOLD + HOLD_COUNT
+ };
+
+ using debounce_base::add;
+
+ public:
+
+ //*************************************************************************
+ /// Constructor.
+ ///\param initial_state The initial state. Default = false.
+ //*************************************************************************
+ debounce(bool initial_state = false)
+ : debounce_base(initial_state)
+ {
+ }
+
+ //*************************************************************************
+ /// Adds a new sample.
+ /// Returns 'true' if the debouncer changes state from...
+ /// 1. Clear to Set.
+ /// 2. Set to Clear.
+ /// 3. Not Held to Held.
+ ///\param sample The new sample.
+ ///\return 'true' if the debouncer changed state.
+ //*************************************************************************
+ bool add(bool sample)
+ {
+ debounce_base::add(sample);
+
+ if (count < HOLD_THRESHOLD)
+ {
+ ++count;
+
+ if (sample)
+ {
+ if (count == VALID_THRESHOLD)
+ {
+ // Set.
+ state |= CHANGED;
+ state |= CURRENT;
+ }
+ else if (count == HOLD_THRESHOLD)
+ {
+ // Held.
+ state |= CHANGED;
+ state |= HELD;
+ }
+
+ state |= LAST;
+ }
+ else
+ {
+ if (count == VALID_THRESHOLD)
+ {
+ // Clear.
+ state |= CHANGED;
+ state &= ~CURRENT;
+ state &= ~HELD;
+ state &= ~REPEATING;
+ }
+
+ state &= ~LAST;
+ }
+ }
+
+ return (state & CHANGED) != 0;
+ }
+ };
+
+ template <const uint16_t VALID_COUNT>
+ class debounce<VALID_COUNT, 0, 0> : public __private_debounce__::debounce_base
+ {
+ private:
+
+ enum
+ {
+ VALID_THRESHOLD = VALID_COUNT
+ };
+
+ using debounce_base::add;
+
+ public:
+
+ //*************************************************************************
+ /// Constructor.
+ ///\param initial_state The initial state. Default = false.
+ //*************************************************************************
+ debounce(bool initial_state = false)
+ : debounce_base(initial_state)
+ {
+ }
+
+ //*************************************************************************
+ /// Adds a new sample.
+ /// Returns 'true' if the debouncer changes state from...
+ /// 1. Clear to Set.
+ /// 2. Set to Clear.
+ ///\param sample The new sample.
+ ///\return 'true' if the debouncer changed state.
+ //*************************************************************************
+ bool add(bool sample)
+ {
+ debounce_base::add(sample);
+
+ if (count < VALID_THRESHOLD)
+ {
+ ++count;
+
+ if (sample)
+ {
+ if (count == VALID_THRESHOLD)
+ {
+ // Set.
+ state |= CHANGED;
+ state |= CURRENT;
+ }
+
+ state |= LAST;
+ }
+ else
+ {
+ if (count == VALID_THRESHOLD)
+ {
+ // Clear.
+ state |= CHANGED;
+ state &= ~CURRENT;
+ state &= ~HELD;
+ state &= ~REPEATING;
+ }
+
+ state &= ~LAST;
+ }
+ }
+
+ return (state & CHANGED) != 0;
+ }
+ };
+
+ template <>
+ class debounce<0, 0, 0> : public __private_debounce__::debounce_base
+ {
+ public:
+
+ using debounce_base::add;
+
+ //*************************************************************************
+ /// Constructor.
+ ///\param initial_state The initial state. Default = false.
+ //*************************************************************************
+ debounce()
+ : debounce_base(false),
+ valid_threshold(1),
+ hold_threshold(0),
+ repeat_threshold(0)
+ {
+ }
+
+ //*************************************************************************
+ /// Constructor.
+ ///\param initial_state The initial state.
+ ///\param valid_count The count for a valid state. Default = 1.
+ ///\param hold_count The count after valid_count for a hold state. Default = 0.
+ ///\param repeat_count The count after hold_count for a key repeat. Default = 0.
+ //*************************************************************************
+ debounce(bool initial_state, uint16_t valid_count = 1, uint16_t hold_count = 0, uint16_t repeat_count = 0)
+ : debounce_base(initial_state)
+ {
+ set(valid_count, hold_count, repeat_count);
+ }
+
+ //*************************************************************************
+ /// Constructor.
+ ///\param initial_state The initial state. Default = false.
+ //*************************************************************************
+ void set(uint16_t valid_count, uint16_t hold_count = 0, uint16_t repeat_count = 0)
+ {
+ valid_threshold = valid_count;
+ hold_threshold = valid_threshold + hold_count;
+ repeat_threshold = hold_threshold + repeat_count;
+ }
+
+ //*************************************************************************
+ /// Adds a new sample.
+ /// Returns 'true' if the debouncer changes state from...
+ /// 1. Clear to Set.
+ /// 2. Set to Clear.
+ /// 3. Not Held to Held.
+ /// 4. Key repeats.
+ ///\param sample The new sample.
+ ///\return 'true' if the debouncer changed state.
+ //*************************************************************************
+ bool add(bool sample)
+ {
+ debounce_base::add(sample);
+
+ if (count < repeat_threshold)
+ {
+ ++count;
+
+ if (sample)
+ {
+ if (count == valid_threshold)
+ {
+ if (sample)
+ {
+ // Set.
+ state |= CHANGED;
+ state |= CURRENT;
+ }
+ }
+
+ if (hold_threshold != valid_threshold)
+ {
+ if ((count == hold_threshold) && sample)
+ {
+ // Held.
+ state |= CHANGED;
+ state |= HELD;
+ }
+ }
+
+ if (repeat_threshold != hold_threshold)
+ {
+ if ((count == repeat_threshold) && sample)
+ {
+ // Repeat.
+ state |= CHANGED;
+ state |= REPEATING;
+ count = hold_threshold;
+ }
+ }
+
+ state |= LAST;
+ }
+ else
+ {
+ if (count == valid_threshold)
+ {
+ // Clear.
+ state |= CHANGED;
+ state &= ~CURRENT;
+ state &= ~HELD;
+ state &= ~REPEATING;
+ }
+
+ state &= ~LAST;
+ }
+ }
+
+ return (state & CHANGED) != 0;
+ }
+
+ private:
+
+ uint16_t valid_threshold;
+ uint16_t hold_threshold;
+ uint16_t repeat_threshold;
+ };
+}
+
+#endif
diff --git a/lib/etl/deque.h b/lib/etl/deque.h
new file mode 100644
index 0000000..08db51d
--- /dev/null
+++ b/lib/etl/deque.h
@@ -0,0 +1,140 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_DEQUE__
+#define __ETL_DEQUE__
+
+#include <stddef.h>
+#include <stdint.h>
+#include <iterator>
+#include <algorithm>
+
+#include "ideque.h"
+#include "container.h"
+#include "alignment.h"
+#include "array.h"
+
+//*****************************************************************************
+///\defgroup deque deque
+/// A double ended queue with the capacity defined at compile time.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+ //***************************************************************************
+ /// A fixed capacity double ended queue.
+ ///\note The deque allocates one more element than the specified maximum size.
+ ///\tparam T The type of items this deque holds.
+ ///\tparam MAX_SIZE_ The capacity of the deque
+ ///\ingroup deque
+ //***************************************************************************
+ template <typename T, const size_t MAX_SIZE_>
+ class deque : public ideque<T>
+ {
+ public:
+
+ static const size_t MAX_SIZE = MAX_SIZE_;
+
+ private:
+
+ static const size_t BUFFER_SIZE = MAX_SIZE + 1;
+
+ public:
+
+ typedef T value_type;
+ typedef T* pointer;
+ typedef const T* const_pointer;
+ typedef T& reference;
+ typedef const T& const_reference;
+ typedef size_t size_type;
+ typedef typename std::iterator_traits<pointer>::difference_type difference_type;
+
+ //*************************************************************************
+ /// Default constructor.
+ //*************************************************************************
+ deque()
+ : ideque<T>(reinterpret_cast<T*>(&buffer[0]), MAX_SIZE, BUFFER_SIZE)
+ {
+ ideque<T>::initialise();
+ }
+
+ //*************************************************************************
+ /// Copy constructor.
+ //*************************************************************************
+ deque(const deque& other)
+ : ideque<T>(reinterpret_cast<T*>(&buffer[0]), MAX_SIZE, BUFFER_SIZE)
+ {
+ if (this != &other)
+ {
+ ideque<T>::assign(other.begin(), other.end());
+ }
+ }
+
+ //*************************************************************************
+ /// Assigns data to the deque.
+ //*************************************************************************
+ template <typename TIterator>
+ deque(TIterator begin, TIterator end)
+ : ideque<T>(reinterpret_cast<T*>(&buffer[0]), MAX_SIZE, BUFFER_SIZE)
+ {
+ ideque<T>::assign(begin, end);
+ }
+
+ //*************************************************************************
+ /// Assigns data to the deque.
+ //*************************************************************************
+ explicit deque(size_t n, typename ideque<T>::parameter_t value = value_type())
+ : ideque<T>(reinterpret_cast<T*>(&buffer[0]), MAX_SIZE, BUFFER_SIZE)
+ {
+ ideque<T>::assign(n, value);
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ deque& operator =(const deque& rhs)
+ {
+ if (&rhs != this)
+ {
+ ideque<T>::assign(rhs.begin(), rhs.end());
+ }
+
+ return *this;
+ }
+
+ private:
+
+ /// The uninitialised buffer of T used in the deque.
+ typename etl::aligned_storage<sizeof(T), etl::alignment_of<T>::value>::type buffer[BUFFER_SIZE];
+ };
+}
+
+#endif
diff --git a/lib/etl/doxygen.h b/lib/etl/doxygen.h
new file mode 100644
index 0000000..4639da8
--- /dev/null
+++ b/lib/etl/doxygen.h
@@ -0,0 +1,55 @@
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+///\defgroup etl Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+///\defgroup containers Containers
+///\ingroup etl
+
+///\defgroup utilities Utilities
+/// A set of utility templates.
+///\ingroup etl
+
+///\defgroup maths Maths
+/// A set of mathematical templates.
+///\ingroup etl
+
+///\defgroup patterns Patterns
+/// A set of templated design patterns.
+///\ingroup etl
+
+///\defgroup crc CRC
+/// A set of CRC calculations
+///\ingroup maths
+
+///\ingroup etl
+namespace etl {}
+
+
diff --git a/lib/etl/endian.h b/lib/etl/endian.h
new file mode 100644
index 0000000..d905d8e
--- /dev/null
+++ b/lib/etl/endian.h
@@ -0,0 +1,91 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_ENDIAN__
+#define __ETL_ENDIAN__
+
+#include <stdint.h>
+
+#include "enum_type.h"
+
+///\defgroup endian endian
+/// Constants & utilities for endianess
+///\ingroup utilities
+
+namespace etl
+{
+ //***************************************************************************
+ /// Constants to denote endianness of operations.
+ ///\ingroup endian
+ //***************************************************************************
+ struct endian
+ {
+ enum enum_type
+ {
+ little,
+ big,
+ native
+ };
+
+ DECLARE_ENUM_TYPE(endian, int)
+ ENUM_TYPE(little, "little")
+ ENUM_TYPE(big, "big")
+ ENUM_TYPE(native, "native")
+ END_ENUM_TYPE
+ };
+
+ //***************************************************************************
+ /// Checks the endianness of the platform.
+ ///\ingroup endian
+ //***************************************************************************
+ struct endianness
+ {
+ endianness()
+ : ETL_ENDIAN_TEST(0x0011)
+ {
+ }
+
+ endian operator ()() const
+ {
+ return endian(*this);
+ }
+
+ operator endian() const
+ {
+ return (*reinterpret_cast<const uint8_t*>(&ETL_ENDIAN_TEST) == 0x11) ? endian::little : endian::big;
+ }
+
+ private:
+
+ const uint16_t ETL_ENDIAN_TEST;
+ };
+}
+
+#endif
diff --git a/lib/etl/enum_type.h b/lib/etl/enum_type.h
new file mode 100644
index 0000000..971e804
--- /dev/null
+++ b/lib/etl/enum_type.h
@@ -0,0 +1,116 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_ENUM_TYPE__
+#define __ETL_ENUM_TYPE__
+
+///\defgroup enum_type enum_type
+/// Smart enumerations.<br>
+/// A method of declaring enumerations that allow grouping within a structure.
+/// Avoids the problem of clashing names that can occur with standard enumerations.
+/// One way to think of the code is as a type with built-in constants and an optional conversion to a string.<br><br>
+/// <b>Declaring the enumeration.</b>
+///\code
+/// struct CompassDirection
+/// {
+/// enum enum_type
+/// {
+/// North = 0,
+/// South = 180,
+/// East = 90,
+/// West = 270
+/// };
+///
+/// DECLARE_ENUM_TYPE(CompassDirection, int)
+/// ENUM_TYPE(North, "North")
+/// ENUM_TYPE(South, "South")
+/// ENUM_TYPE(East, "East")
+/// ENUM_TYPE(West, "West")
+/// END_ENUM_TYPE
+/// };
+///\endcode
+/// <b>Using the enumeration.</b>
+///\code
+/// CompassDirection direction; // Default construction.
+///
+/// direction = CompassDirection::North; // Assignment from an enumeration constant;
+///
+/// int value = direction; // Implicit conversion to 'int'.
+///
+/// direction = CompassDirection(value); // Explicit conversion from 'int'.
+///
+/// direction = CompassDirection(3); // Explicit conversion from an invalid value. This unfortunately cannot be avoided. Caveat emptor!
+///
+/// direction = value; // Implicit conversion from 'int'. **** Compilation error ****
+///
+/// std::cout << "Direction = " << direction.c_str(); // Prints "Direction = North"
+///\endcode
+/// If a conversion to a string is not required then the 'ENUM_TYPE' declaration may be omitted.
+/// In that case the c_str() function will return a "?". This will also be the case for any
+/// enumeration value that does not have an ENUM_TYPE entry.
+///\ingroup utilities
+
+//*****************************************************************************
+// The declaration of the member functions and the first section of the 'c_str' function.
+//*****************************************************************************
+#define DECLARE_ENUM_TYPE(TypeName, ValueType) \
+ typedef ValueType value_type; \
+ TypeName() {} \
+ TypeName(const TypeName &other) : value(other.value) {} \
+ TypeName(enum_type value) : value(value) {} \
+ TypeName& operator=(const TypeName &other) {value = other.value; return *this;} \
+ explicit TypeName(value_type value) : value(static_cast<enum_type>(value)) {} \
+ operator value_type() const {return static_cast<value_type>(value);} \
+ value_type get_value() const {return static_cast<value_type>(value);} \
+ enum_type get_enum() const {return value;} \
+ const char* c_str() const \
+ { \
+ switch (value) \
+ {
+
+//*****************************************************************************
+// A case in the 'c_str' function's switch statement.
+//*****************************************************************************
+#define ENUM_TYPE(value, name) \
+ case value: \
+ return name; \
+
+//*****************************************************************************
+// The final section of the 'c_str' function and the value declaration.
+//*****************************************************************************
+#define END_ENUM_TYPE \
+ default: \
+ return "?"; \
+ } \
+ } \
+private: \
+ enum_type value;
+
+#endif
diff --git a/lib/etl/error_handler.cpp b/lib/etl/error_handler.cpp
new file mode 100644
index 0000000..5a02d22
--- /dev/null
+++ b/lib/etl/error_handler.cpp
@@ -0,0 +1,59 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#include "error_handler.h"
+#include "nullptr.h"
+
+//*****************************************************************************
+/// The error function callback pointer.
+//*****************************************************************************
+etl::ifunction<const etl::exception&>* etl::error_handler::p_ifunction = nullptr;
+
+//*****************************************************************************
+/// Sets the error callback function.
+///\param f A reference to an etl::function object that will handler errors.
+//*****************************************************************************
+void etl::error_handler::set_callback(ifunction<const etl::exception&>& f)
+{
+ p_ifunction = &f;
+}
+
+//*****************************************************************************
+/// Sends the exception error to the user's handler function.
+///\param e The exception error.
+//*****************************************************************************
+void etl::error_handler::error(const etl::exception& e)
+{
+ if (p_ifunction != nullptr)
+ {
+ (*p_ifunction)(e);
+ }
+}
+
diff --git a/lib/etl/error_handler.h b/lib/etl/error_handler.h
new file mode 100644
index 0000000..e9a8bba
--- /dev/null
+++ b/lib/etl/error_handler.h
@@ -0,0 +1,133 @@
+
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_ERROR_HANDLER__
+#define __ETL_ERROR_HANDLER__
+
+///\defgroup error_handler error_handler
+/// Error handler for when throwing exceptions is not required.
+///\ingroup utilities
+
+#include <assert.h>
+
+#include "exception.h"
+#include "function.h"
+
+namespace etl
+{
+ //***************************************************************************
+ /// Error handler for when throwing exceptions is not required.
+ ///\ingroup error_handler
+ //***************************************************************************
+ class error_handler
+ {
+ public:
+
+ //*************************************************************************
+ /// Callback class for free handler functions.
+ //*************************************************************************
+ struct free_function : public etl::function<void, const etl::exception&>
+ {
+ free_function(void (*p_function)(const etl::exception&))
+ : etl::function<void, const etl::exception&>(p_function)
+ {
+ }
+ };
+
+ //*************************************************************************
+ /// Callback class for member handler functions.
+ //*************************************************************************
+ template <typename TObject>
+ struct member_function : public etl::function<TObject, const etl::exception&>
+ {
+ member_function(TObject& object, void(TObject::*p_function)(const etl::exception&))
+ : etl::function<TObject, const etl::exception&>(object, p_function)
+ {
+ }
+ };
+
+ static void set_callback(ifunction<const etl::exception&>& f);
+ static void error(const etl::exception& e);
+
+ private:
+
+ static ifunction<const etl::exception&>* p_ifunction;
+ };
+}
+
+//***************************************************************************
+/// Asserts a condition.
+/// Versions of the macro that return a constant value of 'true' will allow the compiler to optimise away
+/// any 'if' statements that it is contained within.
+/// If ETL_NO_CHECKS is defined then no runtime checks are executed at all.
+/// If asserts or exceptions are enabled then the error is thrown if the assert fails. The return value is always 'true'.
+/// If ETL_LOG_ERRORS is defined then the error is logged if the assert fails. The return value is the value of the boolean test.
+/// Otherwise 'assert' is called. The return value is always 'true'.
+///\ingroup error_handler
+//***************************************************************************
+#if defined(ETL_NO_CHECKS)
+ #define ETL_ASSERT(b, e) // Does nothing.
+#elif defined(ETL_THROW_EXCEPTIONS)
+ #if defined(ETL_LOG_ERRORS)
+ #define ETL_ASSERT(b, e) {if (!(b)) {etl::error_handler::error((e)); throw((e);)}} // If the condition fails, calls the error handler then throws an exception.
+ #else
+ #define ETL_ASSERT(b, e) {if (!(b)) {throw((e));}} // If the condition fails, throws an exception.
+ #endif
+#else
+ #if defined(ETL_LOG_ERRORS)
+ #if defined(NDEBUG)
+ #define ETL_ASSERT(b, e) {if(!(b)) {etl::error_handler::error((e));}} // If the condition fails, calls the error handler
+ #else
+ #define ETL_ASSERT(b, e) {if(!(b)) {etl::error_handler::error((e));} assert((b));} // If the condition fails, calls the error handler then asserts.
+ #endif
+ #else
+ #if defined(NDEBUG)
+ #define ETL_ASSERT(b, e) // Does nothing.
+ #else
+ #define ETL_ASSERT(b, e) assert((b)) // If the condition fails, asserts.
+ #endif
+ #endif
+#endif
+
+#if defined(ETL_VERBOSE_ERRORS)
+ #define ETL_ERROR(e) (e(__FILE__, __LINE__)) // Make an exception with the file name and line number.
+#else
+ #define ETL_ERROR(e) (e("", __LINE__)) // Make an exception with the line number.
+#endif
+
+#if defined(ETL_VERBOSE_ERRORS)
+ #define ETL_ERROR_TEXT(verbose_text, terse_text) (verbose_text) // Use the verbose text.
+#else
+ #define ETL_ERROR_TEXT(verbose_text, terse_text) (terse_text) // Use the terse text.
+#endif
+
+#endif
+
diff --git a/lib/etl/etl_arduino.h b/lib/etl/etl_arduino.h
new file mode 100644
index 0000000..7efdae0
--- /dev/null
+++ b/lib/etl/etl_arduino.h
@@ -0,0 +1,8 @@
+
+
+#ifndef __ETL_PLATFORM_ARDUINO__
+
+#define COMPILER_GCC
+#define PLATFORM_ARM
+
+#endif
diff --git a/lib/etl/exception.h b/lib/etl/exception.h
new file mode 100644
index 0000000..52369ca
--- /dev/null
+++ b/lib/etl/exception.h
@@ -0,0 +1,114 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_EXCEPTION__
+#define __ETL_EXCEPTION__
+
+///\defgroup exception exception
+/// The base class for all ETL exceptions.
+///\ingroup utilities
+
+namespace etl
+{
+ //***************************************************************************
+ ///\ingroup exception
+ /// A low overhead exception base class.
+ //***************************************************************************
+ class exception
+ {
+ public:
+
+ typedef const char* string_type;
+ typedef int numeric_type;
+
+#if defined(ETL_VERBOSE_ERRORS)
+ //*************************************************************************
+ /// Constructor.
+ //*************************************************************************
+ exception(string_type reason, string_type file, numeric_type line)
+ : reason(reason),
+ file(file),
+ line(line)
+ {
+ }
+#else
+ //*************************************************************************
+ /// Constructor.
+ //*************************************************************************
+ exception(string_type reason, string_type file, numeric_type line)
+ : reason(reason),
+ line(line)
+ {
+ }
+#endif
+
+ //***************************************************************************
+ /// Gets the reason for the exception.
+ /// \return const char* to the reason.
+ //***************************************************************************
+ string_type what() const
+ {
+ return reason;
+ }
+
+
+ //***************************************************************************
+ /// Gets the file for the exception.
+ /// \return const char* to the file.
+ //***************************************************************************
+ string_type file_name() const
+ {
+#if defined(ETL_VERBOSE_ERRORS)
+ return file;
+#else
+ return "";
+#endif
+ }
+
+ //***************************************************************************
+ /// Gets the line for the exception.
+ /// \return const char* to the line.
+ //***************************************************************************
+ numeric_type line_number() const
+ {
+ return line;
+ }
+
+ private:
+
+ string_type reason; ///< The reason for the exception.
+#if defined(ETL_VERBOSE_ERRORS)
+ string_type file; ///< The file for the exception.
+#endif
+ numeric_type line; ///< The line for the exception.
+ };
+}
+
+#endif
diff --git a/lib/etl/factorial.h b/lib/etl/factorial.h
new file mode 100644
index 0000000..07dedee
--- /dev/null
+++ b/lib/etl/factorial.h
@@ -0,0 +1,63 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_FACTORIAL__
+#define __ETL_FACTORIAL__
+
+#include <stddef.h>
+
+///\defgroup factorial factorial
+/// fibonacci<N> : Calculates the Nth factorial value.
+///\ingroup maths
+
+namespace etl
+{
+ //***************************************************************************
+ ///\ingroup fibonacci
+ /// Defines <b>value</b> as the Nth factorial number.
+ ///\tparam N The number to find the factorial value of.
+ //***************************************************************************
+ template <size_t N>
+ struct factorial
+ {
+ static const size_t value = N * factorial<N - 1>::value;
+ };
+
+ //***************************************************************************
+ // Specialisation for N = 0
+ //***************************************************************************
+ template <>
+ struct factorial<0>
+ {
+ static const size_t value = 1;
+ };
+}
+
+#endif
diff --git a/lib/etl/fibonacci.h b/lib/etl/fibonacci.h
new file mode 100644
index 0000000..d376511
--- /dev/null
+++ b/lib/etl/fibonacci.h
@@ -0,0 +1,72 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_FIBONACCI__
+#define __ETL_FIBONACCI__
+
+#include <stddef.h>
+
+///\defgroup fibonacci fibonacci
+/// fibonacci<N> : Calculates the Nth Fibonacci value.
+///\ingroup maths
+
+namespace etl
+{
+ //***************************************************************************
+ ///\ingroup fibonacci
+ /// Defines <b>value</b> as the Nth Fibbonacci number.
+ ///\tparam N The number to find the Fibbonacci value of.
+ //***************************************************************************
+ template <size_t N>
+ struct fibonacci
+ {
+ static const size_t value = fibonacci<N - 1>::value + fibonacci<N - 2>::value;
+ };
+
+ //***************************************************************************
+ // Specialisation for N = 1
+ //***************************************************************************
+ template <>
+ struct fibonacci<1>
+ {
+ static const size_t value = 1;
+ };
+
+ //***************************************************************************
+ // Specialisation for N = 0
+ //***************************************************************************
+ template <>
+ struct fibonacci<0>
+ {
+ static const size_t value = 0;
+ };
+}
+
+#endif
diff --git a/lib/etl/file_error_numbers.txt b/lib/etl/file_error_numbers.txt
new file mode 100644
index 0000000..db9728c
--- /dev/null
+++ b/lib/etl/file_error_numbers.txt
@@ -0,0 +1,26 @@
+ 1 deque_base
+ 2 flat_map_base
+ 3 flat_multimap_base
+ 4 flat_multiset_base
+ 5 flat_set_base
+ 6 forward_list_base
+ 7 list_base
+ 8 map_base
+ 9 multimap_base
+10 multiset_base
+11 pool_base
+12 ipriority_queue
+13 queue_base
+14 set_base
+15 stack_base
+16 iunordered_map
+17 vector_base
+18 observer
+19 ihash
+20 intrusive_forward_list
+21 intrusive_list
+22 intrusive_links
+23 iunordered_set, iunordered_multiset
+24 variant
+25 iunordered_multimap
+26 iunordered_multiset \ No newline at end of file
diff --git a/lib/etl/fixed_iterator.h b/lib/etl/fixed_iterator.h
new file mode 100644
index 0000000..1b9d137
--- /dev/null
+++ b/lib/etl/fixed_iterator.h
@@ -0,0 +1,268 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2015 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_FIXED_ITERATOR__
+#define __ETL_FIXED_ITERATOR__
+
+#include <iterator>
+
+///\defgroup iterator Iterator types
+
+namespace etl
+{
+ /// A fixed iterator class.
+ /// This iterator can be given an iterator value, which will not be allowed to be incremented or decremented.
+ /// This can be useful when using STL algorithms to interact with fixed memory locations such as registers.
+ ///\ingroup iterator
+ template <typename TIterator>
+ class fixed_iterator : std::iterator<typename std::iterator_traits<TIterator>::iterator_category, typename std::iterator_traits<TIterator>::value_type>
+ {
+ public:
+
+ //***************************************************************************
+ /// Default constructor.
+ //***************************************************************************
+ fixed_iterator()
+ : it(TIterator())
+ {
+ }
+
+ //***************************************************************************
+ /// Construct from iterator.
+ //***************************************************************************
+ fixed_iterator(TIterator it)
+ : it(it)
+ {
+ }
+
+ //***************************************************************************
+ /// Increment (Does nothing).
+ //***************************************************************************
+ fixed_iterator& operator ++()
+ {
+ return *this;
+ }
+
+ //***************************************************************************
+ /// Increment (Does nothing).
+ //***************************************************************************
+ fixed_iterator operator ++(int)
+ {
+ return *this;
+ }
+
+ //***************************************************************************
+ /// Decrement (Does nothing).
+ //***************************************************************************
+ fixed_iterator& operator --()
+ {
+ return *this;
+ }
+
+ //***************************************************************************
+ /// Decrement (Does nothing).
+ //***************************************************************************
+ fixed_iterator operator --(int)
+ {
+ return *this;
+ }
+
+ //***************************************************************************
+ /// Dereference operator.
+ //***************************************************************************
+ typename std::iterator_traits<TIterator>::value_type operator *()
+ {
+ return *it;
+ }
+
+ //***************************************************************************
+ /// Dereference operator.
+ //***************************************************************************
+ const typename std::iterator_traits<TIterator>::value_type operator *() const
+ {
+ return *it;
+ }
+
+ //***************************************************************************
+ /// -> operator.
+ //***************************************************************************
+ TIterator operator ->()
+ {
+ return it;
+ }
+
+ //***************************************************************************
+ /// -> operator.
+ //***************************************************************************
+ const TIterator operator ->() const
+ {
+ return it;
+ }
+
+ //***************************************************************************
+ /// Conversion operator.
+ //***************************************************************************
+ operator TIterator() const
+ {
+ return it;
+ }
+
+ //***************************************************************************
+ /// += operator.
+ //***************************************************************************
+ fixed_iterator& operator +=(typename std::iterator_traits<TIterator>::difference_type offset)
+ {
+ return *this;
+ }
+
+ //***************************************************************************
+ /// -= operator.
+ //***************************************************************************
+ fixed_iterator& operator -=(typename std::iterator_traits<TIterator>::difference_type offset)
+ {
+ return *this;
+ }
+
+ //***************************************************************************
+ /// Assignment from iterator.
+ //***************************************************************************
+ fixed_iterator& operator =(TIterator new_it)
+ {
+ it = new_it;
+ return *this;
+ }
+
+ //***************************************************************************
+ /// Assignment from fixed_iterator.
+ //***************************************************************************
+ fixed_iterator& operator =(fixed_iterator other)
+ {
+ it = other.it;
+ return *this;
+ }
+
+ private:
+
+ TIterator it; ///< The underlying iterator.
+ };
+}
+
+//*****************************************************************************
+/// + difference operator.
+//*****************************************************************************
+template <typename TIterator>
+etl::fixed_iterator<TIterator>& operator +(etl::fixed_iterator<TIterator>& lhs,
+ typename std::iterator_traits<TIterator>::difference_type rhs)
+{
+ return lhs;
+}
+
+//*****************************************************************************
+/// - difference operator.
+//*****************************************************************************
+template <typename TIterator>
+etl::fixed_iterator<TIterator>& operator -(etl::fixed_iterator<TIterator>& lhs,
+ typename std::iterator_traits<TIterator>::difference_type rhs)
+{
+ return lhs;
+}
+
+//*****************************************************************************
+/// - fixed_iterator operator.
+//*****************************************************************************
+template <typename TIterator>
+typename std::iterator_traits<TIterator>::difference_type operator -(etl::fixed_iterator<TIterator>& lhs,
+ etl::fixed_iterator<TIterator>& rhs)
+{
+ return TIterator(lhs) - TIterator(rhs);
+}
+
+//*****************************************************************************
+/// Equality operator. fixed_iterator == fixed_iterator.
+//*****************************************************************************
+template <typename TIterator>
+bool operator ==(const etl::fixed_iterator<TIterator>& lhs,
+ const etl::fixed_iterator<TIterator>& rhs)
+{
+ return TIterator(lhs) == TIterator(rhs);
+}
+
+//*****************************************************************************
+/// Equality operator. fixed_iterator == iterator.
+//*****************************************************************************
+template <typename TIterator>
+bool operator ==(const etl::fixed_iterator<TIterator>& lhs,
+ TIterator rhs)
+{
+ return TIterator(lhs) == rhs;
+}
+
+//*****************************************************************************
+/// Equality operator. iterator == fixed_iterator.
+//*****************************************************************************
+template <typename TIterator>
+bool operator ==(TIterator lhs,
+ const etl::fixed_iterator<TIterator>& rhs)
+{
+ return lhs == TIterator(rhs);
+}
+
+
+//*****************************************************************************
+/// Inequality operator. fixed_iterator == fixed_iterator.
+//*****************************************************************************
+template <typename TIterator>
+bool operator !=(const etl::fixed_iterator<TIterator>& lhs,
+ const etl::fixed_iterator<TIterator>& rhs)
+{
+ return !(lhs == rhs);
+}
+
+//*****************************************************************************
+/// Inequality operator. fixed_iterator == iterator.
+//*****************************************************************************
+template <typename TIterator>
+bool operator !=(const etl::fixed_iterator<TIterator>& lhs,
+ TIterator rhs)
+{
+ return !(lhs == rhs);
+}
+
+//*****************************************************************************
+/// Inequality operator. iterator == fixed_iterator.
+//*****************************************************************************
+template <typename TIterator>
+bool operator !=(TIterator& lhs,
+ const etl::fixed_iterator<TIterator>& rhs)
+{
+ return !(lhs == rhs);
+}
+
+#endif
diff --git a/lib/etl/flat_map.h b/lib/etl/flat_map.h
new file mode 100644
index 0000000..f323a36
--- /dev/null
+++ b/lib/etl/flat_map.h
@@ -0,0 +1,115 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2015 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_FLAT_MAP__
+#define __ETL_FLAT_MAP__
+
+#include <stddef.h>
+#include <iterator>
+#include <functional>
+
+#include "iflat_map.h"
+#include "vector.h"
+
+//*****************************************************************************
+///\defgroup flat_map flat_map
+/// A flat_map with the capacity defined at compile time.
+/// Has insertion of O(N) and flat_map of O(logN)
+/// Duplicate entries and not allowed.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+ template <typename TKey, typename TValue, const size_t MAX_SIZE_, typename TCompare = std::less<TKey> >
+ //***************************************************************************
+ /// A flat_map implementation that uses a fixed size buffer.
+ ///\tparam TKey The key type.
+ ///\tparam TValue The value type.
+ ///\tparam TCompare The type to compare keys. Default = std::less<TKey>
+ ///\tparam MAX_SIZE_ The maximum number of elements that can be stored.
+ ///\ingroup flat_map
+ //***************************************************************************
+ class flat_map : public iflat_map<TKey, TValue, TCompare>
+ {
+ public:
+
+ static const size_t MAX_SIZE = MAX_SIZE_;
+
+ //*************************************************************************
+ /// Constructor.
+ //*************************************************************************
+ flat_map()
+ : iflat_map<TKey, TValue, TCompare>(buffer)
+ {
+ }
+
+ //*************************************************************************
+ /// Copy constructor.
+ //*************************************************************************
+ flat_map(const flat_map& other)
+ : iflat_map<TKey, TValue, TCompare>(buffer)
+ {
+ iflat_map<TKey, TValue, TCompare>::assign(other.cbegin(), other.cend());
+ }
+
+ //*************************************************************************
+ /// Constructor, from an iterator range.
+ ///\tparam TIterator The iterator type.
+ ///\param first The iterator to the first element.
+ ///\param last The iterator to the last element + 1.
+ //*************************************************************************
+ template <typename TIterator>
+ flat_map(TIterator first, TIterator last)
+ : iflat_map<TKey, TValue, TCompare>(buffer)
+ {
+ iflat_map<TKey, TValue, TCompare>::assign(first, last);
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ flat_map& operator = (const flat_map& rhs)
+ {
+ if (&rhs != this)
+ {
+ iflat_map<TKey, TValue, TCompare>::assign(rhs.cbegin(), rhs.cend());
+ }
+
+ return *this;
+ }
+
+ private:
+
+ etl::vector<typename iflat_map<TKey, TValue, TCompare>::value_type, MAX_SIZE> buffer; ///<The vector that stores the elements.
+ };
+}
+
+#endif
diff --git a/lib/etl/flat_multimap.h b/lib/etl/flat_multimap.h
new file mode 100644
index 0000000..b0d3722
--- /dev/null
+++ b/lib/etl/flat_multimap.h
@@ -0,0 +1,115 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2015 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_FLAT_MULTMAP__
+#define __ETL_FLAT_MULTMAP__
+
+#include <stddef.h>
+#include <iterator>
+#include <functional>
+
+#include "iflat_multimap.h"
+#include "vector.h"
+
+//*****************************************************************************
+///\defgroup flat_multimap flat_multimap
+/// A flat_multimapmap with the capacity defined at compile time.
+/// Has insertion of O(N) and find of O(logN)
+/// Duplicate entries and not allowed.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+ template <typename TKey, typename TValue, const size_t MAX_SIZE_, typename TCompare = std::less<TKey> >
+ //***************************************************************************
+ /// A flat_multimap implementation that uses a fixed size buffer.
+ ///\tparam TKey The key type.
+ ///\tparam TValue The value type.
+ ///\tparam TCompare The type to compare keys. Default = std::less<TKey>
+ ///\tparam MAX_SIZE_ The maximum number of elements that can be stored.
+ ///\ingroup flat_multimap
+ //***************************************************************************
+ class flat_multimap : public iflat_multimap<TKey, TValue, TCompare>
+ {
+ public:
+
+ static const size_t MAX_SIZE = MAX_SIZE_;
+
+ //*************************************************************************
+ /// Constructor.
+ //*************************************************************************
+ flat_multimap()
+ : iflat_multimap<TKey, TValue, TCompare>(buffer)
+ {
+ }
+
+ //*************************************************************************
+ /// Copy constructor.
+ //*************************************************************************
+ flat_multimap(const flat_multimap& other)
+ : iflat_multimap<TKey, TValue, TCompare>(buffer)
+ {
+ iflat_multimap<TKey, TValue, TCompare>::assign(other.cbegin(), other.cend());
+ }
+
+ //*************************************************************************
+ /// Constructor, from an iterator range.
+ ///\tparam TIterator The iterator type.
+ ///\param first The iterator to the first element.
+ ///\param last The iterator to the last element + 1.
+ //*************************************************************************
+ template <typename TIterator>
+ flat_multimap(TIterator first, TIterator last)
+ : iflat_multimap<TKey, TValue, TCompare>(buffer)
+ {
+ iflat_multimap<TKey, TValue, TCompare>::assign(first, last);
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ flat_multimap& operator = (const flat_multimap& rhs)
+ {
+ if (&rhs != this)
+ {
+ iflat_multimap<TKey, TValue, TCompare>::assign(rhs.cbegin(), rhs.cend());
+ }
+
+ return *this;
+ }
+
+ private:
+
+ etl::vector<typename iflat_multimap<TKey, TValue, TCompare>::value_type, MAX_SIZE> buffer; ///<The vector that stores the elements.
+ };
+}
+
+#endif
diff --git a/lib/etl/flat_multiset.h b/lib/etl/flat_multiset.h
new file mode 100644
index 0000000..3f5c47f
--- /dev/null
+++ b/lib/etl/flat_multiset.h
@@ -0,0 +1,114 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2015 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_FLAT_MULTISET__
+#define __ETL_FLAT_MULTISET__
+
+#include <stddef.h>
+#include <iterator>
+#include <functional>
+
+#include "iflat_multiset.h"
+#include "vector.h"
+
+//*****************************************************************************
+///\defgroup flat_multiset flat_multiset
+/// A flat_multiset with the capacity defined at compile time.
+/// Has insertion of O(N) and flat_multiset of O(logN)
+/// Duplicate entries and not allowed.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+ template <typename T, const size_t MAX_SIZE_, typename TCompare = std::less<T> >
+ //***************************************************************************
+ /// A flat_multiset implementation that uses a fixed size buffer.
+ ///\tparam T The value type.
+ ///\tparam TCompare The type to compare keys. Default = std::less<T>
+ ///\tparam MAX_SIZE_ The maximum number of elements that can be stored.
+ ///\ingroup flat_multiset
+ //***************************************************************************
+ class flat_multiset : public iflat_multiset<T, TCompare>
+ {
+ public:
+
+ static const size_t MAX_SIZE = MAX_SIZE_;
+
+ //*************************************************************************
+ /// Constructor.
+ //*************************************************************************
+ flat_multiset()
+ : iflat_multiset<T, TCompare>(buffer)
+ {
+ }
+
+ //*************************************************************************
+ /// Copy constructor.
+ //*************************************************************************
+ flat_multiset(const flat_multiset& other)
+ : iflat_multiset<T, TCompare>(buffer)
+ {
+ iflat_multiset<T, TCompare>::assign(other.cbegin(), other.cend());
+ }
+
+ //*************************************************************************
+ /// Constructor, from an iterator range.
+ ///\tparam TIterator The iterator type.
+ ///\param first The iterator to the first element.
+ ///\param last The iterator to the last element + 1.
+ //*************************************************************************
+ template <typename TIterator>
+ flat_multiset(TIterator first, TIterator last)
+ : iflat_multiset<T, TCompare>(buffer)
+ {
+ iflat_multiset<T, TCompare>::assign(first, last);
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ flat_multiset& operator = (const flat_multiset& rhs)
+ {
+ if (&rhs != this)
+ {
+ iflat_multiset<T, TCompare>::assign(rhs.cbegin(), rhs.cend());
+ }
+
+ return *this;
+ }
+
+ private:
+
+ etl::vector<T, MAX_SIZE> buffer; ///<The vector that stores the elements.
+ };
+}
+
+#endif
diff --git a/lib/etl/flat_set.h b/lib/etl/flat_set.h
new file mode 100644
index 0000000..07ce888
--- /dev/null
+++ b/lib/etl/flat_set.h
@@ -0,0 +1,114 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2015 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_FLAT_SET__
+#define __ETL_FLAT_SET__
+
+#include <stddef.h>
+#include <iterator>
+#include <functional>
+
+#include "iflat_set.h"
+#include "vector.h"
+
+//*****************************************************************************
+///\defgroup flat_set flat_set
+/// A flat_set with the capacity defined at compile time.
+/// Has insertion of O(N) and flat_set of O(logN)
+/// Duplicate entries and not allowed.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+ template <typename T, const size_t MAX_SIZE_, typename TCompare = std::less<T> >
+ //***************************************************************************
+ /// A flat_set implementation that uses a fixed size buffer.
+ ///\tparam T The value type.
+ ///\tparam TCompare The type to compare keys. Default = std::less<T>
+ ///\tparam MAX_SIZE_ The maximum number of elements that can be stored.
+ ///\ingroup flat_set
+ //***************************************************************************
+ class flat_set : public iflat_set<T, TCompare>
+ {
+ public:
+
+ static const size_t MAX_SIZE = MAX_SIZE_;
+
+ //*************************************************************************
+ /// Constructor.
+ //*************************************************************************
+ flat_set()
+ : iflat_set<T, TCompare>(buffer)
+ {
+ }
+
+ //*************************************************************************
+ /// Copy constructor.
+ //*************************************************************************
+ flat_set(const flat_set& other)
+ : iflat_set<T, TCompare>(buffer)
+ {
+ iflat_set<T, TCompare>::assign(other.cbegin(), other.cend());
+ }
+
+ //*************************************************************************
+ /// Constructor, from an iterator range.
+ ///\tparam TIterator The iterator type.
+ ///\param first The iterator to the first element.
+ ///\param last The iterator to the last element + 1.
+ //*************************************************************************
+ template <typename TIterator>
+ flat_set(TIterator first, TIterator last)
+ : iflat_set<T, TCompare>(buffer)
+ {
+ iflat_set<T, TCompare>::assign(first, last);
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ flat_set& operator = (const flat_set& rhs)
+ {
+ if (&rhs != this)
+ {
+ iflat_set<T, TCompare>::assign(rhs.cbegin(), rhs.cend());
+ }
+
+ return *this;
+ }
+
+ private:
+
+ etl::vector<T, MAX_SIZE> buffer; ///<The vector that stores the elements.
+ };
+}
+
+#endif
diff --git a/lib/etl/fnv_1.h b/lib/etl/fnv_1.h
new file mode 100644
index 0000000..5ae00da
--- /dev/null
+++ b/lib/etl/fnv_1.h
@@ -0,0 +1,427 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_FNV_1__
+#define __ETL_FNV_1__
+
+#include <stdint.h>
+
+#include "platform.h"
+#include "static_assert.h"
+#include "type_traits.h"
+#include "ihash.h"
+
+#if defined(ETL_COMPILER_KEIL)
+#pragma diag_suppress 1300
+#endif
+
+///\defgroup fnv_1 FNV-1 & FNV-1a 32 & 64 bit hash calculations
+///\ingroup maths
+
+namespace etl
+{
+ //***************************************************************************
+ /// Calculates the fnv_1_64 hash.
+ ///\ingroup fnv_1_64
+ //***************************************************************************
+ class fnv_1_64
+ {
+ public:
+
+ typedef uint64_t value_type;
+
+ //*************************************************************************
+ /// Default constructor.
+ //*************************************************************************
+ fnv_1_64()
+ {
+ reset();
+ }
+
+ //*************************************************************************
+ /// Constructor from range.
+ /// \param begin Start of the range.
+ /// \param end End of the range.
+ //*************************************************************************
+ template<typename TIterator>
+ fnv_1_64(TIterator begin, const TIterator end)
+ {
+ STATIC_ASSERT(sizeof(typename std::iterator_traits<TIterator>::value_type) == 1, "Type not supported");
+
+ reset();
+ while (begin != end)
+ {
+ hash *= PRIME;
+ hash ^= *begin++;
+ }
+ }
+
+ //*************************************************************************
+ /// Resets the CRC to the initial state.
+ //*************************************************************************
+ void reset()
+ {
+ hash = OFFSET_BASIS;
+ }
+
+ //*************************************************************************
+ /// Adds a range.
+ /// \param begin
+ /// \param end
+ //*************************************************************************
+ template<typename TIterator>
+ void add(TIterator begin, const TIterator end)
+ {
+ STATIC_ASSERT(sizeof(typename std::iterator_traits<TIterator>::value_type) == 1, "Type not supported");
+
+ while (begin != end)
+ {
+ hash *= PRIME;
+ hash ^= *begin++;
+ }
+ }
+
+ //*************************************************************************
+ /// \param value The char to add to the fnv_1_64.
+ //*************************************************************************
+ void add(uint8_t value)
+ {
+ hash *= PRIME;
+ hash ^= value;
+ }
+
+ //*************************************************************************
+ /// Gets the fnv_1_64 value.
+ //*************************************************************************
+ value_type value() const
+ {
+ return hash;
+ }
+
+ //*************************************************************************
+ /// Conversion operator to value_type.
+ //*************************************************************************
+ operator value_type () const
+ {
+ return hash;
+ }
+
+ private:
+
+ value_type hash;
+
+ static const uint64_t OFFSET_BASIS = 0xCBF29CE484222325;
+ static const uint64_t PRIME = 0x00000100000001b3;
+ };
+
+ //***************************************************************************
+ /// Calculates the fnv_1a_64 hash.
+ ///\ingroup fnv_1a_64
+ //***************************************************************************
+ class fnv_1a_64
+ {
+ public:
+
+ typedef uint64_t value_type;
+
+ //*************************************************************************
+ /// Default constructor.
+ //*************************************************************************
+ fnv_1a_64()
+ {
+ reset();
+ }
+
+ //*************************************************************************
+ /// Constructor from range.
+ /// \param begin Start of the range.
+ /// \param end End of the range.
+ //*************************************************************************
+ template<typename TIterator>
+ fnv_1a_64(TIterator begin, const TIterator end)
+ {
+ STATIC_ASSERT(sizeof(typename std::iterator_traits<TIterator>::value_type) == 1, "Type not supported");
+
+ reset();
+ while (begin != end)
+ {
+ hash ^= *begin++;
+ hash *= PRIME;
+ }
+ }
+
+ //*************************************************************************
+ /// Resets the CRC to the initial state.
+ //*************************************************************************
+ void reset()
+ {
+ hash = OFFSET_BASIS;
+ }
+
+ //*************************************************************************
+ /// Adds a range.
+ /// \param begin
+ /// \param end
+ //*************************************************************************
+ template<typename TIterator>
+ void add(TIterator begin, const TIterator end)
+ {
+ STATIC_ASSERT(sizeof(typename std::iterator_traits<TIterator>::value_type) == 1, "Type not supported");
+
+ while (begin != end)
+ {
+ hash ^= *begin++;
+ hash *= PRIME;
+ }
+ }
+
+ //*************************************************************************
+ /// \param value The char to add to the fnv_1a_64.
+ //*************************************************************************
+ void add(uint8_t value)
+ {
+ hash ^= value;
+ hash *= PRIME;
+ }
+
+ //*************************************************************************
+ /// Gets the fnv_1a_64 value.
+ //*************************************************************************
+ value_type value() const
+ {
+ return hash;
+ }
+
+ //*************************************************************************
+ /// Conversion operator to value_type.
+ //*************************************************************************
+ operator value_type () const
+ {
+ return hash;
+ }
+
+ private:
+
+ value_type hash;
+
+ static const uint64_t OFFSET_BASIS = 0xCBF29CE484222325;
+ static const uint64_t PRIME = 0x00000100000001b3;
+ };
+
+ //***************************************************************************
+ /// Calculates the fnv_1_32 hash.
+ ///\ingroup fnv_1_32
+ //***************************************************************************
+ class fnv_1_32
+ {
+ public:
+
+ typedef uint32_t value_type;
+
+ //*************************************************************************
+ /// Default constructor.
+ //*************************************************************************
+ fnv_1_32()
+ {
+ reset();
+ }
+
+ //*************************************************************************
+ /// Constructor from range.
+ /// \param begin Start of the range.
+ /// \param end End of the range.
+ //*************************************************************************
+ template<typename TIterator>
+ fnv_1_32(TIterator begin, const TIterator end)
+ {
+ STATIC_ASSERT(sizeof(typename std::iterator_traits<TIterator>::value_type) == 1, "Type not supported");
+
+ reset();
+ while (begin != end)
+ {
+ hash *= PRIME;
+ hash ^= *begin++;
+ }
+ }
+
+ //*************************************************************************
+ /// Resets the CRC to the initial state.
+ //*************************************************************************
+ void reset()
+ {
+ hash = OFFSET_BASIS;
+ }
+
+ //*************************************************************************
+ /// Adds a range.
+ /// \param begin
+ /// \param end
+ //*************************************************************************
+ template<typename TIterator>
+ void add(TIterator begin, const TIterator end)
+ {
+ STATIC_ASSERT(sizeof(typename std::iterator_traits<TIterator>::value_type) == 1, "Type not supported");
+
+ while (begin != end)
+ {
+ hash *= PRIME;
+ hash ^= *begin++;
+ }
+ }
+
+ //*************************************************************************
+ /// \param value The char to add to the fnv_1_32.
+ //*************************************************************************
+ void add(uint8_t value)
+ {
+ hash *= PRIME;
+ hash ^= value;
+ }
+
+ //*************************************************************************
+ /// Gets the fnv_1_32 value.
+ //*************************************************************************
+ value_type value() const
+ {
+ return hash;
+ }
+
+ //*************************************************************************
+ /// Conversion operator to value_type.
+ //*************************************************************************
+ operator value_type () const
+ {
+ return hash;
+ }
+
+ private:
+
+ value_type hash;
+
+ static const uint32_t OFFSET_BASIS = 0x811C9DC5;
+ static const uint32_t PRIME = 0x01000193;
+ };
+
+ //***************************************************************************
+ /// Calculates the fnv_1a_32 hash.
+ ///\ingroup fnv_1a_32
+ //***************************************************************************
+ class fnv_1a_32
+ {
+ public:
+
+ typedef uint32_t value_type;
+
+ //*************************************************************************
+ /// Default constructor.
+ //*************************************************************************
+ fnv_1a_32()
+ {
+ reset();
+ }
+
+ //*************************************************************************
+ /// Constructor from range.
+ /// \param begin Start of the range.
+ /// \param end End of the range.
+ //*************************************************************************
+ template<typename TIterator>
+ fnv_1a_32(TIterator begin, const TIterator end)
+ {
+ STATIC_ASSERT(sizeof(typename std::iterator_traits<TIterator>::value_type) == 1, "Type not supported");
+
+ reset();
+ while (begin != end)
+ {
+ hash ^= *begin++;
+ hash *= PRIME;
+ }
+ }
+
+ //*************************************************************************
+ /// Resets the CRC to the initial state.
+ //*************************************************************************
+ void reset()
+ {
+ hash = OFFSET_BASIS;
+ }
+
+ //*************************************************************************
+ /// Adds a range.
+ /// \param begin
+ /// \param end
+ //*************************************************************************
+ template<typename TIterator>
+ void add(TIterator begin, const TIterator end)
+ {
+ STATIC_ASSERT(sizeof(typename std::iterator_traits<TIterator>::value_type) == 1, "Type not supported");
+
+ while (begin != end)
+ {
+ hash ^= *begin++;
+ hash *= PRIME;
+ }
+ }
+
+ //*************************************************************************
+ /// \param value The char to add to the fnv_1a_32.
+ //*************************************************************************
+ void add(uint8_t value)
+ {
+ hash ^= value;
+ hash *= PRIME;
+ }
+
+ //*************************************************************************
+ /// Gets the fnv_1a_32 value.
+ //*************************************************************************
+ value_type value() const
+ {
+ return hash;
+ }
+
+ //*************************************************************************
+ /// Conversion operator to value_type.
+ //*************************************************************************
+ operator value_type () const
+ {
+ return hash;
+ }
+
+ private:
+
+ value_type hash;
+
+ static const uint32_t OFFSET_BASIS = 0x811C9DC5;
+ static const uint32_t PRIME = 0x01000193;
+ };
+}
+
+#endif
diff --git a/lib/etl/forward_list.h b/lib/etl/forward_list.h
new file mode 100644
index 0000000..8ca6119
--- /dev/null
+++ b/lib/etl/forward_list.h
@@ -0,0 +1,125 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_LIST__
+#define __ETL_LIST__
+
+#include <stddef.h>
+
+#include "pool.h"
+#include "iforward_list.h"
+#include "container.h"
+
+//*****************************************************************************
+///\defgroup forward_list forward_list
+/// A linked forward_list with the capacity defined at compile time.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+ //*************************************************************************
+ /// A templated forward_list implementation that uses a fixed size pool.
+ ///\note 'merge' and 'splice_after' and are not supported.
+ //*************************************************************************
+ template <typename T, const size_t MAX_SIZE_>
+ class forward_list : public iforward_list<T>
+ {
+ public:
+
+ static const size_t MAX_SIZE = MAX_SIZE_;
+
+ public:
+
+ typedef T value_type;
+ typedef T* pointer;
+ typedef const T* const_pointer;
+ typedef T& reference;
+ typedef const T& const_reference;
+ typedef size_t size_type;
+
+ //*************************************************************************
+ /// Default constructor.
+ //*************************************************************************
+ forward_list()
+ : iforward_list<T>(node_pool, MAX_SIZE)
+ {
+ iforward_list<T>::initialise();
+ }
+
+ //*************************************************************************
+ /// Construct from size and value.
+ //*************************************************************************
+ explicit forward_list(size_t initial_size, typename iforward_list<T>::parameter_t value = T())
+ : iforward_list<T>(node_pool, MAX_SIZE)
+ {
+ iforward_list<T>::assign(initial_size, value);
+ }
+
+ //*************************************************************************
+ /// Copy constructor.
+ //*************************************************************************
+ forward_list(const forward_list& other)
+ : iforward_list<T>(node_pool, MAX_SIZE)
+ {
+ iforward_list<T>::assign(other.cbegin(), other.cend());
+ }
+
+ //*************************************************************************
+ /// Construct from range.
+ //*************************************************************************
+ template <typename TIterator>
+ forward_list(TIterator first, TIterator last)
+ : iforward_list<T>(node_pool, MAX_SIZE)
+ {
+ iforward_list<T>::assign(first, last);
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ forward_list& operator = (const forward_list& rhs)
+ {
+ if (&rhs != this)
+ {
+ iforward_list<T>::assign(rhs.cbegin(), rhs.cend());
+ }
+
+ return *this;
+ }
+
+ private:
+
+ /// The pool of nodes used in the list.
+ etl::pool<typename iforward_list<T>::Data_Node, MAX_SIZE> node_pool;
+ };
+}
+
+#endif
diff --git a/lib/etl/frame_check_sequence.h b/lib/etl/frame_check_sequence.h
new file mode 100644
index 0000000..74dc774
--- /dev/null
+++ b/lib/etl/frame_check_sequence.h
@@ -0,0 +1,133 @@
+
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+Copyright(c) 2014 jwellbelove
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_FRAME_CHECK_SEQUENCE__
+#define __ETL_FRAME_CHECK_SEQUENCE__
+
+#include <stdint.h>
+
+#include "static_assert.h"
+#include "type_traits.h"
+#include "binary.h"
+
+///\defgroup frame_check_sequence Frame check sequence calculation
+///\ingroup maths
+
+namespace etl
+{
+ //***************************************************************************
+ /// Calculates a frame check sequence according to the specified policy.
+ ///\tparam TPolicy The type used to enact the policy.
+ ///\ingroup frame_check_sequence
+ //***************************************************************************
+ template <typename TPolicy>
+ class frame_check_sequence
+ {
+ public:
+
+ typedef TPolicy policy_type;
+ typedef typename policy_type::value_type value_type;
+
+ STATIC_ASSERT(etl::is_unsigned<value_type>::value, "Signed frame check type not supported");
+
+ //*************************************************************************
+ /// Default constructor.
+ //*************************************************************************
+ frame_check_sequence()
+ {
+ reset();
+ }
+
+ //*************************************************************************
+ /// Constructor from range.
+ /// \param begin Start of the range.
+ /// \param end End of the range.
+ //*************************************************************************
+ template<typename TIterator>
+ frame_check_sequence(TIterator begin, const TIterator end)
+ {
+ STATIC_ASSERT(sizeof(typename std::iterator_traits<TIterator>::value_type) == 1, "Type not supported");
+
+ reset();
+ add(begin, end);
+ }
+
+ //*************************************************************************
+ /// Resets the FCS to the initial state.
+ //*************************************************************************
+ void reset()
+ {
+ frame_check = policy.initial();
+ }
+
+ //*************************************************************************
+ /// Adds a range.
+ /// \param begin
+ /// \param end
+ //*************************************************************************
+ template<typename TIterator>
+ void add(TIterator begin, const TIterator end)
+ {
+ STATIC_ASSERT(sizeof(typename std::iterator_traits<TIterator>::value_type) == 1, "Type not supported");
+
+ while (begin != end)
+ {
+ frame_check = policy.add(frame_check, *begin++);
+ }
+ }
+
+ //*************************************************************************
+ /// \param value The uint8_t to add to the FCS.
+ //*************************************************************************
+ void add(uint8_t value)
+ {
+ frame_check = policy.add(frame_check, value);
+ }
+
+ //*************************************************************************
+ /// Gets the FCS value.
+ //*************************************************************************
+ value_type value() const
+ {
+ return policy.final(frame_check);
+ }
+
+ //*************************************************************************
+ /// Conversion operator to value_type.
+ //*************************************************************************
+ operator value_type () const
+ {
+ return policy.final(frame_check);
+ }
+
+ private:
+
+ value_type frame_check;
+ policy_type policy;
+ };
+}
+
+#endif
diff --git a/lib/etl/function.h b/lib/etl/function.h
new file mode 100644
index 0000000..caf7b4c
--- /dev/null
+++ b/lib/etl/function.h
@@ -0,0 +1,223 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_FUNCTION__
+#define __ETL_FUNCTION__
+
+//*****************************************************************************
+///\defgroup function function
+/// A set of wrapper templates to allow a member or static function to be called
+/// without the caller having to know the specific details of the callee.
+/// This template class may be used to link interrupt vectors to specific member
+/// functions of a handler class.
+///\ingroup utilities
+//*****************************************************************************
+
+namespace etl
+{
+ //***************************************************************************
+ ///\ingroup function
+ /// The base interface template for function template specialisations.
+ ///\tparam TParameter The parameter type expected by the function.
+ //***************************************************************************
+ template <typename TParameter>
+ class ifunction
+ {
+ public:
+
+ typedef TParameter parameter_type; ///< The type of parameter sent to the function.
+
+ //*************************************************************************
+ /// The function operator that will be overridden.
+ //*************************************************************************
+ virtual void operator ()(TParameter) = 0;
+ };
+
+ //***************************************************************************
+ ///\ingroup function
+ /// The base interface template for functions taking <b>void</b> parameters.
+ //***************************************************************************
+ template <>
+ class ifunction<void>
+ {
+ public:
+
+ typedef void parameter_type; ///< The type of parameter sent to the function.
+
+ //*************************************************************************
+ /// The function operator that will be overridden.
+ //*************************************************************************
+ virtual void operator ()() = 0;
+ };
+
+ //***************************************************************************
+ ///\ingroup function
+ /// A derived function template that takes an object type and parameter type.
+ ///\tparam TObject The object type that contains the member function.
+ ///\tparam TParameter The parameter type accepted by the member function.
+ //***************************************************************************
+ template <typename TObject, typename TParameter>
+ class function : public ifunction<TParameter>
+ {
+ public:
+
+ typedef TObject object_type; ///< The type of object.
+ typedef TParameter parameter_type; ///< The type of parameter sent to the function.
+
+ //*************************************************************************
+ /// Constructor.
+ ///\param object Reference to the object
+ ///\param p_function Pointer to the member function
+ //*************************************************************************
+ function(TObject& object, void(TObject::* p_function)(TParameter))
+ : p_object(&object),
+ p_function(p_function)
+ {
+ }
+
+ //*************************************************************************
+ /// The function operator that calls the destination function.
+ ///\param data The data to pass to the function.
+ //*************************************************************************
+ virtual void operator ()(TParameter data)
+ {
+ // Call the object's member function with the data.
+ (p_object->*p_function)(data);
+ }
+
+ private:
+
+ TObject* p_object; ///< Pointer to the object that contains the function.
+ void (TObject::* p_function)(TParameter); ///< Pointer to the member function.
+ };
+
+ //***************************************************************************
+ ///\ingroup function
+ /// A derived function template that takes a parameter type.
+ ///\tparam TObject The object type that contains the member function.
+ //***************************************************************************
+ template <typename TObject>
+ class function<TObject, void> : public ifunction<void>
+ {
+ public:
+
+ //*************************************************************************
+ /// Constructor.
+ ///\param object Reference to the object
+ ///\param p_function Pointer to the member function
+ //*************************************************************************
+ function(TObject& object, void(TObject::* p_function)(void))
+ : p_object(&object),
+ p_function(p_function)
+ {
+ }
+
+ //*************************************************************************
+ /// The function operator that calls the destination function.
+ //*************************************************************************
+ virtual void operator ()()
+ {
+ // Call the object's member function.
+ (p_object->*p_function)();
+ }
+
+ private:
+
+ TObject* p_object; ///< Pointer to the object that contains the function.
+ void (TObject::* p_function)(); ///< Pointer to the member function.
+ };
+
+ //***************************************************************************
+ ///\ingroup function
+ /// Specialisation for static or global functions that takes a parameter.
+ //***************************************************************************
+ template <typename TParameter>
+ class function<void, TParameter> : public ifunction<TParameter>
+ {
+ public:
+
+ //*************************************************************************
+ /// Constructor.
+ ///\param p_function Pointer to the function
+ //*************************************************************************
+ function(void(*p_function)(TParameter))
+ : p_function(p_function)
+ {
+ }
+
+ //*************************************************************************
+ /// The function operator that calls the destination function.
+ ///\param data The data to pass to the function.
+ //*************************************************************************
+ virtual void operator ()(TParameter data)
+ {
+ // Call the function with the data.
+ (*p_function)(data);
+ }
+
+ private:
+
+ void (*p_function)(TParameter); ///< Pointer to the function.
+ };
+
+ //***************************************************************************
+ ///\ingroup function
+ /// Specialisation static functions taking void parameter.
+ //***************************************************************************
+ template <>
+ class function<void, void> : public ifunction<void>
+ {
+ public:
+
+ //*************************************************************************
+ /// Constructor.
+ ///\param p_function Pointer to the function.
+ //*************************************************************************
+ function(void(*p_function)(void))
+ : p_function(p_function)
+ {
+ }
+
+ //*************************************************************************
+ /// The function operator that calls the destination function.
+ //*************************************************************************
+ virtual void operator ()()
+ {
+ // Call the function.
+ (*p_function)();
+ }
+
+ private:
+
+ void (*p_function)(); ///< Pointer to the function.
+ };
+}
+
+#endif
diff --git a/lib/etl/functional.h b/lib/etl/functional.h
new file mode 100644
index 0000000..3135398
--- /dev/null
+++ b/lib/etl/functional.h
@@ -0,0 +1,109 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_FUNCTIONAL__
+#define __ETL_FUNCTIONAL__
+
+///\defgroup functional functional
+///\ingroup utilities
+
+///\defgroup reference_wrapper reference_wrapper
+///\ingroup functional
+
+namespace etl
+{
+ //***************************************************************************
+ /// A definition of reference_wrapper for those that don't have C++ 0x11 support.
+ ///\ingroup reference
+ //***************************************************************************
+ template <typename T>
+ class reference_wrapper
+ {
+ public:
+
+ typedef T type;
+
+ explicit reference_wrapper(T& t_)
+ : t(&t_)
+ {
+ }
+
+ operator T& () const
+ {
+ return *t;
+ }
+
+ reference_wrapper<T>& operator = (T value)
+ {
+ *t = value;
+ return *this;
+ }
+
+ T& get() const
+ {
+ return *t;
+ }
+
+ private:
+
+ T* t;
+ };
+
+ //***************************************************************************
+ template <typename T>
+ reference_wrapper<T> ref(T& t)
+ {
+ return reference_wrapper<T>(t);
+ }
+
+ //***************************************************************************
+ template <typename T>
+ reference_wrapper<T> ref(reference_wrapper<T> t)
+ {
+ return reference_wrapper<T>(t.get());
+ }
+
+ //***************************************************************************
+ template <typename T>
+ reference_wrapper<const T> cref(const T& t)
+ {
+ return reference_wrapper<const T>(t);
+ }
+
+ //***************************************************************************
+ template <typename T>
+ reference_wrapper<const T> cref(reference_wrapper<T> t)
+ {
+ return reference_wrapper<const T>(t.get());
+ }
+}
+
+#endif
+
diff --git a/lib/etl/hash.h b/lib/etl/hash.h
new file mode 100644
index 0000000..3d02ab9
--- /dev/null
+++ b/lib/etl/hash.h
@@ -0,0 +1,401 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_HASH__
+#define __ETL_HASH__
+
+#include <stdint.h>
+
+// The default hash calculation.
+#include "fnv_1.h"
+#include "type_traits.h"
+#include "static_assert.h"
+
+///\defgroup hash Standard hash calculations
+///\ingroup maths
+
+namespace etl
+{
+ namespace __private_hash__
+ {
+ //*************************************************************************
+ /// Hash to use when size_t is 16 bits.
+ /// T is always expected to be size_t.
+ //*************************************************************************
+ template <typename T>
+ typename enable_if<sizeof(T) == sizeof(uint16_t), size_t>::type
+ generic_hash(uint8_t* begin, uint8_t* end)
+ {
+ uint32_t h = fnv_1a_32(begin, end);
+
+ return static_cast<size_t>(h ^ (h >> 16));
+ }
+
+ //*************************************************************************
+ /// Hash to use when size_t is 32 bits.
+ /// T is always expected to be size_t.
+ //*************************************************************************
+ template <typename T>
+ typename enable_if<sizeof(T) == sizeof(uint32_t), size_t>::type
+ generic_hash(uint8_t* begin, uint8_t* end)
+ {
+ return fnv_1a_32(begin, end);
+ }
+
+ //*************************************************************************
+ /// Hash to use when size_t is 64 bits.
+ /// T is always expected to be size_t.
+ //*************************************************************************
+ template <typename T>
+ typename enable_if<sizeof(T) == sizeof(uint64_t), size_t>::type
+ generic_hash(uint8_t* begin, uint8_t* end)
+ {
+ return fnv_1a_64(begin, end);
+ }
+ }
+
+ //***************************************************************************
+ /// Generic declaration for etl::hash
+ ///\ingroup hash
+ //***************************************************************************
+ template <typename T> struct hash;
+
+ //***************************************************************************
+ /// Specialisation for bool.
+ ///\ingroup hash
+ //***************************************************************************
+ template <>
+ struct hash <bool>
+ {
+ STATIC_ASSERT(sizeof(size_t) >= sizeof(bool), "size_t smaller than type");
+
+ size_t operator ()(bool v) const
+ {
+ return static_cast<size_t>(v);
+ }
+ };
+
+ //***************************************************************************
+ /// Specialisation for char.
+ ///\ingroup hash
+ //***************************************************************************
+ template <>
+ struct hash<char>
+ {
+ STATIC_ASSERT(sizeof(size_t) >= sizeof(char), "size_t smaller than type");
+
+ size_t operator ()(char v) const
+ {
+ return static_cast<size_t>(v);
+ }
+ };
+
+ //***************************************************************************
+ /// Specialisation for signed char.
+ ///\ingroup hash
+ //***************************************************************************
+ template<> struct
+ hash<signed char>
+ {
+ STATIC_ASSERT(sizeof(size_t) >= sizeof(signed char), "size_t smaller than type");
+
+ size_t operator ()(signed char v) const
+ {
+ return static_cast<size_t>(v);
+ }
+ };
+
+ //***************************************************************************
+ /// Specialisation for unsigned char.
+ ///\ingroup hash
+ //***************************************************************************
+ template<>
+ struct hash<unsigned char>
+ {
+ STATIC_ASSERT(sizeof(size_t) >= sizeof(unsigned char), "size_t smaller than type");
+
+ size_t operator ()(unsigned char v) const
+ {
+ return static_cast<size_t>(v);
+ }
+ };
+
+ //***************************************************************************
+ /// Specialisation for wchar_t.
+ ///\ingroup hash
+ //***************************************************************************
+ template<>
+ struct hash<wchar_t>
+ {
+ STATIC_ASSERT(sizeof(size_t) >= sizeof(wchar_t), "size_t smaller than type");
+
+ size_t operator ()(wchar_t v) const
+ {
+ return static_cast<size_t>(v);
+ }
+ };
+
+ //***************************************************************************
+ /// Specialisation for short.
+ ///\ingroup hash
+ //***************************************************************************
+ template<>
+ struct hash<short>
+ {
+ STATIC_ASSERT(sizeof(size_t) >= sizeof(short), "size_t smaller than type");
+
+ size_t operator ()(short v) const
+ {
+ return static_cast<size_t>(v);
+ }
+ };
+
+ //***************************************************************************
+ /// Specialisation for unsigned short.
+ ///\ingroup hash
+ //***************************************************************************
+ template<>
+ struct hash<unsigned short>
+ {
+ STATIC_ASSERT(sizeof(size_t) >= sizeof(unsigned short), "size_t smaller than type");
+
+ size_t operator ()(unsigned short v) const
+ {
+ return static_cast<size_t>(v);
+ }
+ };
+
+ //***************************************************************************
+ /// Specialisation for int.
+ ///\ingroup hash
+ //***************************************************************************
+ template<>
+ struct hash<int>
+ {
+ STATIC_ASSERT(sizeof(size_t) >= sizeof(int), "size_t smaller than type");
+
+ size_t operator ()(int v) const
+ {
+ return static_cast<size_t>(v);
+ }
+ };
+
+ //***************************************************************************
+ /// Specialisation for unsigned int.
+ ///\ingroup hash
+ //***************************************************************************
+ template<>
+ struct hash<unsigned int>
+ {
+ STATIC_ASSERT(sizeof(size_t) >= sizeof(unsigned int), "size_t smaller than type");
+
+ size_t operator ()(unsigned int v) const
+ {
+ return static_cast<size_t>(v);
+ }
+ };
+
+ //***************************************************************************
+ /// Specialisation for long.
+ ///\ingroup hash
+ //***************************************************************************
+ template<>
+ struct hash<long>
+ {
+ // If it fits into a size_t.
+ size_t operator ()(long v) const
+ {
+ if (sizeof(size_t) >= sizeof(v))
+ {
+ return static_cast<size_t>(v);
+ }
+ else
+ {
+ uint8_t* p = reinterpret_cast<uint8_t*>(&v);
+ return __private_hash__::generic_hash<size_t>(p, p + sizeof(v));
+ }
+ }
+ };
+
+ //***************************************************************************
+ /// Specialisation for long long.
+ ///\ingroup hash
+ //***************************************************************************
+ template<>
+ struct hash<long long>
+ {
+ // If it fits into a size_t.
+ size_t operator ()(long long v) const
+ {
+ if (sizeof(size_t) >= sizeof(v))
+ {
+ return static_cast<size_t>(v);
+ }
+ else
+ {
+ uint8_t* p = reinterpret_cast<uint8_t*>(&v);
+ return __private_hash__::generic_hash<size_t>(p, p + sizeof(v));
+ }
+ }
+ };
+
+ //***************************************************************************
+ /// Specialisation for unsigned long.
+ ///\ingroup hash
+ //***************************************************************************
+ template<>
+ struct hash<unsigned long>
+ {
+ // If it fits into a size_t.
+ size_t operator ()(unsigned long v) const
+ {
+ if (sizeof(size_t) >= sizeof(v))
+ {
+ return static_cast<size_t>(v);
+ }
+ else
+ {
+ uint8_t* p = reinterpret_cast<uint8_t*>(&v);
+ return __private_hash__::generic_hash<size_t>(p, p + sizeof(v));
+ }
+ }
+ };
+
+ //***************************************************************************
+ /// Specialisation for unsigned long long.
+ ///\ingroup hash
+ //***************************************************************************
+ template<>
+ struct hash<unsigned long long>
+ {
+ // If it fits into a size_t.
+ size_t operator ()(unsigned long long v) const
+ {
+ if (sizeof(size_t) >= sizeof(v))
+ {
+ return static_cast<size_t>(v);
+ }
+ else
+ {
+ uint8_t* p = reinterpret_cast<uint8_t*>(&v);
+ return __private_hash__::generic_hash<size_t>(p, p + sizeof(v));
+ }
+ }
+ };
+
+ //***************************************************************************
+ /// Specialisation for float.
+ ///\ingroup hash
+ //***************************************************************************
+ template<>
+ struct hash<float>
+ {
+ // If it's the same size as a size_t.
+ size_t operator ()(float v) const
+ {
+ if (sizeof(size_t) == sizeof(v))
+ {
+ return *reinterpret_cast<size_t*>(&v);
+ }
+ else
+ {
+ uint8_t* p = reinterpret_cast<uint8_t*>(&v);
+ return __private_hash__::generic_hash<size_t>(p, p + sizeof(v));
+ }
+ }
+ };
+
+ //***************************************************************************
+ /// Specialisation for double.
+ ///\ingroup hash
+ //***************************************************************************
+ template<>
+ struct hash<double>
+ {
+ // If it's the same size as a size_t.
+ size_t operator ()(double v) const
+ {
+ if (sizeof(size_t) == sizeof(v))
+ {
+ return *reinterpret_cast<size_t*>(&v);
+ }
+ else
+ {
+ uint8_t* p = reinterpret_cast<uint8_t*>(&v);
+ return __private_hash__::generic_hash<size_t>(p, p + sizeof(v));
+ }
+ }
+ };
+
+ //***************************************************************************
+ /// Specialisation for long double.
+ ///\ingroup hash
+ //***************************************************************************
+ template<>
+ struct hash<long double>
+ {
+ // If it's the same size as a size_t.
+ size_t operator ()(long double v) const
+ {
+ if (sizeof(size_t) == sizeof(v))
+ {
+ return *reinterpret_cast<size_t*>(&v);
+ }
+ else
+ {
+ uint8_t* p = reinterpret_cast<uint8_t*>(&v);
+ return __private_hash__::generic_hash<size_t>(p, p + sizeof(v));
+ }
+ }
+ };
+
+ //***************************************************************************
+ /// Specialisation for pointers.
+ ///\ingroup hash
+ //***************************************************************************
+ template <typename T>
+ struct hash<T*>
+ {
+ size_t operator ()(const T* v) const
+ {
+ if (sizeof(size_t) == sizeof(T*))
+ {
+ return reinterpret_cast<size_t>(v);
+ }
+ else
+ {
+ uint8_t* p = reinterpret_cast<uint8_t*>(&v);
+ return __private_hash__::generic_hash<size_t>(p, p + sizeof(v));
+ }
+ }
+ };
+}
+
+#endif
diff --git a/lib/etl/ibasic_string.h b/lib/etl/ibasic_string.h
new file mode 100644
index 0000000..275f032
--- /dev/null
+++ b/lib/etl/ibasic_string.h
@@ -0,0 +1,2030 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_ISTRING__
+#define __ETL_ISTRING__
+#define __ETL_IN_ISTRING_H__
+
+#include <iterator>
+#include <algorithm>
+#include <functional>
+#include <stddef.h>
+#include <cstring>
+
+#include "private/string_base.h"
+#include "platform.h"
+#include "algorithm.h"
+#include "type_traits.h"
+#include "error_handler.h"
+#include "algorithm.h"
+#include "char_traits.h"
+
+#ifdef ETL_COMPILER_GCC
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#endif
+
+#ifdef ETL_COMPILER_MICROSOFT
+ #undef min
+#endif
+
+namespace etl
+{
+ //***************************************************************************
+ /// Alternative strlen for all character types.
+ //***************************************************************************
+ template <typename T>
+ size_t strlen(const T* t)
+ {
+ return etl::char_traits<T>::length(t);
+ }
+
+ //***************************************************************************
+ /// The base class for specifically sized strings.
+ /// Can be used as a reference type for all strings containing a specific type.
+ ///\ingroup string
+ //***************************************************************************
+ template <typename T>
+ class ibasic_string : public string_base
+ {
+ public:
+
+ typedef T value_type;
+ typedef T& reference;
+ typedef const T& const_reference;
+ typedef T* pointer;
+ typedef const T* const_pointer;
+ typedef T* iterator;
+ typedef const T* const_iterator;
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+ typedef size_t size_type;
+
+ typedef typename std::iterator_traits<iterator>::difference_type difference_type;
+
+ //*********************************************************************
+ /// Returns an iterator to the beginning of the string.
+ ///\return An iterator to the beginning of the string.
+ //*********************************************************************
+ iterator begin()
+ {
+ return &p_buffer[0];
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the beginning of the string.
+ ///\return A const iterator to the beginning of the string.
+ //*********************************************************************
+ const_iterator begin() const
+ {
+ return &p_buffer[0];
+ }
+
+ //*********************************************************************
+ /// Returns an iterator to the end of the string.
+ ///\return An iterator to the end of the string.
+ //*********************************************************************
+ iterator end()
+ {
+ return &p_buffer[current_size];
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the end of the string.
+ ///\return A const iterator to the end of the string.
+ //*********************************************************************
+ const_iterator end() const
+ {
+ return &p_buffer[current_size];
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the beginning of the string.
+ ///\return A const iterator to the beginning of the string.
+ //*********************************************************************
+ const_iterator cbegin() const
+ {
+ return &p_buffer[0];
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the end of the string.
+ ///\return A const iterator to the end of the string.
+ //*********************************************************************
+ const_iterator cend() const
+ {
+ return &p_buffer[current_size];
+ }
+
+ //*********************************************************************
+ /// Returns an reverse iterator to the reverse beginning of the string.
+ ///\return Iterator to the reverse beginning of the string.
+ //*********************************************************************
+ reverse_iterator rbegin()
+ {
+ return reverse_iterator(end());
+ }
+
+ //*********************************************************************
+ /// Returns a const reverse iterator to the reverse beginning of the string.
+ ///\return Const iterator to the reverse beginning of the string.
+ //*********************************************************************
+ const_reverse_iterator rbegin() const
+ {
+ return const_reverse_iterator(end());
+ }
+
+ //*********************************************************************
+ /// Returns a reverse iterator to the end + 1 of the string.
+ ///\return Reverse iterator to the end + 1 of the string.
+ //*********************************************************************
+ reverse_iterator rend()
+ {
+ return reverse_iterator(begin());
+ }
+
+ //*********************************************************************
+ /// Returns a const reverse iterator to the end + 1 of the string.
+ ///\return Const reverse iterator to the end + 1 of the string.
+ //*********************************************************************
+ const_reverse_iterator rend() const
+ {
+ return const_reverse_iterator(begin());
+ }
+
+ //*********************************************************************
+ /// Returns a const reverse iterator to the reverse beginning of the string.
+ ///\return Const reverse iterator to the reverse beginning of the string.
+ //*********************************************************************
+ const_reverse_iterator crbegin() const
+ {
+ return const_reverse_iterator(cend());
+ }
+
+ //*********************************************************************
+ /// Returns a const reverse iterator to the end + 1 of the string.
+ ///\return Const reverse iterator to the end + 1 of the string.
+ //*********************************************************************
+ const_reverse_iterator crend() const
+ {
+ return const_reverse_iterator(cbegin());
+ }
+
+ //*********************************************************************
+ /// Resizes the string.
+ /// If asserts or exceptions are enabled and the new size is larger than the
+ ///\param new_size The new size.
+ //*********************************************************************
+ void resize(size_t new_size)
+ {
+ resize(new_size, 0);
+ }
+
+ //*********************************************************************
+ /// Resizes the string.
+ ///\param new_size The new size.
+ ///\param value The value to fill new elements with. Default = default constructed value.
+ //*********************************************************************
+ void resize(size_t new_size, T value)
+ {
+ new_size = std::min(new_size, MAX_SIZE);
+
+ // Size up?
+ if (new_size > current_size)
+ {
+ std::fill(p_buffer + current_size, p_buffer + new_size, value);
+ }
+
+ current_size = new_size;
+ p_buffer[new_size] = 0;
+ }
+
+ //*********************************************************************
+ /// Returns a reference to the value at index 'i'
+ ///\param i The index.
+ ///\return A reference to the value at index 'i'
+ //*********************************************************************
+ reference operator [](size_t i)
+ {
+ return p_buffer[i];
+ }
+
+ //*********************************************************************
+ /// Returns a const reference to the value at index 'i'
+ ///\param i The index.
+ ///\return A const reference to the value at index 'i'
+ //*********************************************************************
+ const_reference operator [](size_t i) const
+ {
+ return p_buffer[i];
+ }
+
+ //*********************************************************************
+ /// Returns a reference to the value at index 'i'
+ /// If asserts or exceptions are enabled, emits an etl::string_out_of_bounds if the index is out of range.
+ ///\param i The index.
+ ///\return A reference to the value at index 'i'
+ //*********************************************************************
+ reference at(size_t i)
+ {
+ ETL_ASSERT(i < size(), ETL_ERROR(string_out_of_bounds));
+ return p_buffer[i];
+ }
+
+ //*********************************************************************
+ /// Returns a const reference to the value at index 'i'
+ /// If asserts or exceptions are enabled, emits an etl::string_out_of_bounds if the index is out of range.
+ ///\param i The index.
+ ///\return A const reference to the value at index 'i'
+ //*********************************************************************
+ const_reference at(size_t i) const
+ {
+ ETL_ASSERT(i < size(), ETL_ERROR(string_out_of_bounds));
+ return p_buffer[i];
+ }
+
+ //*********************************************************************
+ /// Returns a reference to the first element.
+ ///\return A reference to the first element.
+ //*********************************************************************
+ reference front()
+ {
+ return p_buffer[0];
+ }
+
+ //*********************************************************************
+ /// Returns a const reference to the first element.
+ ///\return A const reference to the first element.
+ //*********************************************************************
+ const_reference front() const
+ {
+ return p_buffer[0];
+ }
+
+ //*********************************************************************
+ /// Returns a reference to the last element.
+ ///\return A reference to the last element.
+ //*********************************************************************
+ reference back()
+ {
+ return p_buffer[current_size - 1];
+ }
+
+ //*********************************************************************
+ /// Returns a const reference to the last element.
+ ///\return A const reference to the last element.
+ //*********************************************************************
+ const_reference back() const
+ {
+ return p_buffer[current_size - 1];
+ }
+
+ //*********************************************************************
+ /// Returns a pointer to the beginning of the string data.
+ ///\return A pointer to the beginning of the string data.
+ //*********************************************************************
+ pointer data()
+ {
+ return p_buffer;
+ }
+
+ //*********************************************************************
+ /// Returns a const pointer to the beginning of the string data.
+ ///\return A const pointer to the beginning of the string data.
+ //*********************************************************************
+ const_pointer data() const
+ {
+ return p_buffer;
+ }
+
+ //*********************************************************************
+ /// Assigns values to the string.
+ /// Truncates if the string does not have enough free space.
+ ///\param other The other string.
+ //*********************************************************************
+ void assign(const etl::ibasic_string<T>& other)
+ {
+ size_t length = std::min(MAX_SIZE, other.size());
+ assign(other.begin(), other.begin() + length);
+ }
+
+ //*********************************************************************
+ /// Assigns values to the string.
+ /// Truncates if the string does not have enough free space.
+ ///\param other The other string.
+ ///\param subposition The position to start from.
+ ///\param sublength The length to copy.
+ //*********************************************************************
+ void assign(const etl::ibasic_string<T>& other, size_t subposition, size_t sublength)
+ {
+ if (sublength == npos)
+ {
+ sublength = other.size() - subposition;
+ }
+
+ ETL_ASSERT(subposition <= other.size(), ETL_ERROR(string_out_of_bounds));
+
+ assign(other.begin() + subposition, sublength);
+ }
+
+ //*********************************************************************
+ /// Assigns values to the string.
+ /// Truncates if the string does not have enough free space.
+ ///\param other The other string.
+ //*********************************************************************
+ void assign(const_pointer other)
+ {
+ initialise();
+
+ while ((*other != 0) && (current_size < MAX_SIZE))
+ {
+ p_buffer[current_size++] = *other++;
+ }
+
+ is_truncated = (*other != 0);
+
+ p_buffer[current_size] = 0;
+ }
+
+ //*********************************************************************
+ /// Assigns values to the string.
+ /// Truncates if the string does not have enough free space.
+ ///\param other The other string.
+ ///\param length The length to copy.
+ //*********************************************************************
+ void assign(const_pointer other, size_t length)
+ {
+ length = std::min(length, MAX_SIZE);
+
+ initialise();
+
+ etl::copy_n(other, length, begin());
+
+ current_size = length;
+ p_buffer[current_size] = 0;
+ }
+
+ //*********************************************************************
+ /// Assigns values to the string.
+ /// If asserts or exceptions are enabled, emits string_iterator if the iterators are reversed.
+ /// Truncates if the string does not have enough free space.
+ ///\param first The iterator to the first element.
+ ///\param last The iterator to the last element + 1.
+ //*********************************************************************
+ template <typename TIterator>
+ void assign(TIterator first, TIterator last)
+ {
+#ifdef _DEBUG
+ difference_type count = std::distance(first, last);
+ ETL_ASSERT(count >= 0, ETL_ERROR(string_iterator));
+#endif
+
+ initialise();
+
+ while ((first != last) && (current_size != MAX_SIZE))
+ {
+ p_buffer[current_size++] = *first++;
+ }
+
+ p_buffer[current_size] = 0;
+ }
+
+ //*********************************************************************
+ /// Assigns values to the string.
+ /// Truncates if the string does not have enough free space.
+ ///\param n The number of elements to add.
+ ///\param value The value to insert for each element.
+ //*********************************************************************
+ void assign(size_t n, T value)
+ {
+ initialise();
+
+ n = std::min(n, MAX_SIZE);
+
+ std::fill_n(begin(), n, value);
+ current_size = n;
+ p_buffer[current_size] = 0;
+ }
+
+ //*************************************************************************
+ /// Clears the string.
+ //*************************************************************************
+ void clear()
+ {
+ initialise();
+ }
+
+ //*********************************************************************
+ /// Inserts a value at the end of the string.
+ /// Sets 'truncated' if the string is already full.
+ ///\param value The value to add.
+ //*********************************************************************
+ void push_back(T value)
+ {
+ if (current_size != MAX_SIZE)
+ {
+ p_buffer[current_size++] = value;
+ is_truncated = false;
+ }
+ else
+ {
+ is_truncated = true;
+ }
+ }
+
+ //*************************************************************************
+ /// Removes an element from the end of the string.
+ /// Does nothing if the string is empty.
+ //*************************************************************************
+ void pop_back()
+ {
+ if (current_size > 0)
+ {
+ p_buffer[--current_size] = 0;
+ }
+ }
+
+ //*********************************************************************
+ /// Appends to the string.
+ ///\param str The string to append.
+ //*********************************************************************
+ ibasic_string& append(const ibasic_string& str)
+ {
+ insert(end(), str.begin(), str.end());
+ return *this;
+ }
+
+ //*********************************************************************
+ /// Appends to the string.
+ ///\param str The string to append.
+ ///\param subposition The position in str.
+ ///\param sublength The number of characters.
+ //*********************************************************************
+ ibasic_string& append(const ibasic_string& str, size_t subposition, size_t sublength = npos)
+ {
+ ETL_ASSERT(subposition <= str.size(), ETL_ERROR(string_out_of_bounds));
+
+ insert(size(), str, subposition, sublength);
+ return *this;
+ }
+
+ //*********************************************************************
+ /// Appends to the string.
+ ///\param str The string to append.
+ //*********************************************************************
+ ibasic_string& append(const T* str)
+ {
+ insert(size(), str);
+ return *this;
+ }
+
+ //*********************************************************************
+ /// Appends to the string.
+ ///\param str The string to append.
+ ///\param n The number of characters.
+ //*********************************************************************
+ ibasic_string& append(const T* str, size_t n)
+ {
+ insert(size(), str, n);
+ return *this;
+ }
+
+ //*********************************************************************
+ /// Appends to the string.
+ ///\param n The number of characters.
+ ///\param c The character.
+ //*********************************************************************
+ ibasic_string& append(size_t n, T c)
+ {
+ insert(size(), n, c);
+ return *this;
+ }
+
+ //*********************************************************************
+ /// Appends to the string.
+ ///\param first The first of the characters to append.
+ ///\param last The last + 1 character to add.
+ //*********************************************************************
+ template <class TIterator>
+ ibasic_string& append(TIterator first, TIterator last)
+ {
+ insert(end(), first, last);
+ return *this;
+ }
+
+ //*********************************************************************
+ /// Inserts a value to the string.
+ ///\param position The position to insert before.
+ ///\param value The value to insert.
+ //*********************************************************************
+ iterator insert(const_iterator position, T value)
+ {
+ is_truncated = false;
+
+ // Quick hack, as iterators are pointers.
+ iterator insert_position = const_cast<iterator>(position);
+
+ if (current_size < MAX_SIZE)
+ {
+ // Not full yet.
+ if (position != end())
+ {
+ // Insert in the middle.
+ ++current_size;
+ std::copy_backward(insert_position, end() - 1, end());
+ *insert_position = value;
+ }
+ else
+ {
+ // Insert at the end.
+ *insert_position = value;
+ ++current_size;
+ }
+ }
+ else
+ {
+ // Already full.
+ if (position != end())
+ {
+ // Insert in the middle.
+ std::copy_backward(insert_position, end() - 1, end());
+ *insert_position = value;
+ }
+
+ is_truncated = true;
+ }
+
+ p_buffer[current_size] = 0;
+
+ return insert_position;
+ }
+
+ //*********************************************************************
+ /// Inserts 'n' values to the string.
+ ///\param position The position to insert before.
+ ///\param n The number of elements to add.
+ ///\param value The value to insert.
+ //*********************************************************************
+ void insert(const_iterator position, size_t n, T value)
+ {
+ is_truncated = false;
+
+ if (n == 0)
+ {
+ return;
+ }
+
+ // Quick hack, as iterators are pointers.
+ iterator insert_position = const_cast<iterator>(position);
+ const size_t start = std::distance(cbegin(), position);
+
+ // No effect.
+ if (start == MAX_SIZE)
+ {
+ return;
+ }
+
+ // Fills the string to the end?
+ if ((start + n) >= MAX_SIZE)
+ {
+ is_truncated = ((current_size + n) > MAX_SIZE);
+ current_size = MAX_SIZE;
+ std::fill(insert_position, end(), value);
+ }
+ else
+ {
+ // Lets do some shifting.
+ const size_t shift_amount = n;
+ const size_t to_position = start + shift_amount;
+ const size_t remaining_characters = current_size - start;
+ const size_t max_shift_characters = MAX_SIZE - start - shift_amount;
+ const size_t characters_to_shift = std::min(max_shift_characters, remaining_characters);
+
+ // Will the string truncate?
+ if ((start + shift_amount + remaining_characters) > MAX_SIZE)
+ {
+ current_size = MAX_SIZE;
+ is_truncated = true;
+ }
+ else
+ {
+ current_size += shift_amount;
+ }
+
+ std::copy_backward(insert_position, insert_position + characters_to_shift, begin() + to_position + characters_to_shift);
+ std::fill(insert_position, insert_position + shift_amount, value);
+ }
+
+ p_buffer[current_size] = 0;
+ }
+
+ //*********************************************************************
+ /// Inserts a range of values to the string.
+ /// If asserts or exceptions are enabled, emits string_full if the string does not have enough free space.
+ ///\param position The position to insert before.
+ ///\param first The first element to add.
+ ///\param last The last + 1 element to add.
+ //*********************************************************************
+ template <class TIterator>
+ void insert(iterator position, TIterator first, TIterator last)
+ {
+ is_truncated = false;
+
+ if (first == last)
+ {
+ return;
+ }
+
+ const size_t start = std::distance(begin(), position);
+ const size_t n = std::distance(first, last);
+
+ // No effect.
+ if (start == MAX_SIZE)
+ {
+ return;
+ }
+
+ // Fills the string to the end?
+ if ((start + n) >= MAX_SIZE)
+ {
+ is_truncated = ((current_size + n) > MAX_SIZE);
+ current_size = MAX_SIZE;
+
+ while (position != end())
+ {
+ *position++ = *first++;
+ }
+ }
+ else
+ {
+ // Lets do some shifting.
+ const size_t shift_amount = n;
+ const size_t to_position = start + shift_amount;
+ const size_t remaining_characters = current_size - start;
+ const size_t max_shift_characters = MAX_SIZE - start - shift_amount;
+ const size_t characters_to_shift = std::min(max_shift_characters, remaining_characters);
+
+ // Will the string truncate?
+ if ((start + shift_amount + remaining_characters) > MAX_SIZE)
+ {
+ current_size = MAX_SIZE;
+ is_truncated = true;
+ }
+ else
+ {
+ current_size += shift_amount;
+ }
+
+ std::copy_backward(position, position + characters_to_shift, begin() + to_position + characters_to_shift);
+
+ while (first != last)
+ {
+ *position++ = *first++;
+ }
+ }
+
+ p_buffer[current_size] = 0;
+ }
+
+ //*********************************************************************
+ /// Inserts a string at the specified position.
+ ///\param position The position to insert before.
+ ///\param str The string to insert.
+ //*********************************************************************
+ etl::ibasic_string<T>& insert(size_t position, const etl::ibasic_string<T>& str)
+ {
+ ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds));
+
+ insert(begin() + position, str.cbegin(), str.cend());
+ return *this;
+ }
+
+ //*********************************************************************
+ /// Inserts a string at the specified position from subposition for sublength.
+ ///\param position The position to insert before.
+ ///\param str The string to insert.
+ ///\param subposition The subposition to start from.
+ ///\param sublength The number of characters to insert.
+ //*********************************************************************
+ etl::ibasic_string<T>& insert(size_t position, const etl::ibasic_string<T>& str, size_t subposition, size_t sublength)
+ {
+ ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds));
+ ETL_ASSERT(subposition <= str.size(), ETL_ERROR(string_out_of_bounds));
+
+ if ((sublength == npos) || (subposition + sublength > str.size()))
+ {
+ sublength = str.size() - subposition;
+ }
+
+ insert(begin() + position, str.cbegin() + subposition, str.cbegin() + subposition + sublength);
+ return *this;
+ }
+
+ //*********************************************************************
+ /// Inserts a string at the specified position from pointer.
+ ///\param position The position to insert before.
+ ///\param s The string to insert.
+ //*********************************************************************
+ etl::ibasic_string<T>& insert(size_t position, const_pointer s)
+ {
+ ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds));
+
+ insert(begin() + position, s, s + strlen(s));
+ return *this;
+ }
+
+ //*********************************************************************
+ /// Inserts a string at the specified position from pointer for n characters.
+ ///\param position The position to insert before.
+ ///\param s The string to insert.
+ ///\param n The number of characters to insert.
+ //*********************************************************************
+ etl::ibasic_string<T>& insert(size_t position, const_pointer s, size_t n)
+ {
+ ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds));
+
+ insert(begin() + position, s, s + n);
+ return *this;
+ }
+
+ //*********************************************************************
+ /// Insert n characters of c at position.
+ ///\param position The position to insert before.
+ ///\param n The number of characters to insert.
+ ///\param c The character to insert.
+ //*********************************************************************
+ etl::ibasic_string<T>& insert(size_t position, size_t n, value_type c)
+ {
+ ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds));
+
+ insert(begin() + position, n, c);
+ return *this;
+ }
+
+ //*********************************************************************
+ /// Erases a sequence.
+ ///\param position Position to start from.
+ ///\param length Number of characters.
+ ///\return A refernce to this string.
+ //*********************************************************************
+ etl::ibasic_string<T>& erase(size_t position, size_t length = npos)
+ {
+ // Limit the length.
+ length = std::min(length, size() - position);
+
+ erase(begin() + position, begin() + position + length);
+
+ return *this;
+ }
+
+ //*********************************************************************
+ /// Erases an element.
+ ///\param i_element Iterator to the element.
+ ///\return An iterator pointing to the element that followed the erased element.
+ //*********************************************************************
+ iterator erase(iterator i_element)
+ {
+ std::copy(i_element + 1, end(), i_element);
+ p_buffer[--current_size] = 0;
+
+ return i_element;
+ }
+
+ //*********************************************************************
+ /// Erases a range of elements.
+ /// The range includes all the elements between first and last, including the
+ /// element pointed by first, but not the one pointed by last.
+ ///\param first Iterator to the first element.
+ ///\param last Iterator to the last element.
+ ///\return An iterator pointing to the element that followed the erased element.
+ //*********************************************************************
+ iterator erase(iterator first, iterator last)
+ {
+ std::copy(last, end(), first);
+ size_t n_delete = std::distance(first, last);
+
+ current_size -= n_delete;
+ p_buffer[current_size] = 0;
+
+ return first;
+ }
+
+ //*********************************************************************
+ /// Return a pointer to a C string.
+ //*********************************************************************
+ const_pointer c_str() const
+ {
+ return p_buffer;
+ }
+
+ //*********************************************************************
+ /// Copies a portion of a string.
+ ///\param s Pointer to the string to copy.
+ ///\param len The number of characters to copy.
+ ///\param pos The position to start copying from.
+ //*********************************************************************
+ size_t copy(pointer s, size_t len, size_t pos = 0)
+ {
+ size_t endpos = std::min(pos + len, size());
+
+ for (size_t i = pos; i < endpos; ++i)
+ {
+ *s++ = p_buffer[i];
+ }
+
+ return endpos - pos;
+ }
+
+ //*********************************************************************
+ /// Find content within the string
+ ///\param str The content to find
+ ///\param pos The position to start searching from.
+ //*********************************************************************
+ size_t find(const ibasic_string<T>& str, size_t pos = 0) const
+ {
+ if ((pos + str.size()) > size())
+ {
+ return npos;
+ }
+
+ const_iterator iposition = std::search(begin() + pos, end(), str.begin(), str.end());
+
+ if (iposition == end())
+ {
+ return npos;
+ }
+ else
+ {
+ return std::distance(begin(), iposition);
+ }
+ }
+
+ //*********************************************************************
+ /// Find content within the string
+ ///\param s Pointer to the content to find
+ ///\param pos The position to start searching from.
+ //*********************************************************************
+ size_t find(const_pointer s, size_t pos = 0) const
+ {
+#ifdef _DEBUG
+ if ((pos + etl::strlen(s)) > size())
+ {
+ return npos;
+ }
+#endif
+
+ const_iterator iposition = std::search(begin() + pos, end(), s, s + etl::strlen(s));
+
+ if (iposition == end())
+ {
+ return npos;
+ }
+ else
+ {
+ return std::distance(begin(), iposition);
+ }
+ }
+
+ //*********************************************************************
+ /// Find content within the string
+ ///\param s Pointer to the content to find
+ ///\param pos The position to start searching from.
+ ///\param n The number of characters to search for.
+ //*********************************************************************
+ size_t find(const_pointer s, size_t pos, size_t n) const
+ {
+#ifdef _DEBUG
+ if ((pos + etl::strlen(s) - n) > size())
+ {
+ return npos;
+ }
+#endif
+
+ const_iterator iposition = std::search(begin() + pos, end(), s, s + n);
+
+ if (iposition == end())
+ {
+ return npos;
+ }
+ else
+ {
+ return std::distance(begin(), iposition);
+ }
+ }
+
+ //*********************************************************************
+ /// Find character within the string
+ ///\param c The character to find.
+ ///\param position The position to start searching from.
+ //*********************************************************************
+ size_t find(T c, size_t position = 0) const
+ {
+ const_iterator i = std::find(begin() + position, end(), c);
+
+ if (i != end())
+ {
+ return std::distance(begin(), i);
+ }
+ else
+ {
+ return npos;
+ }
+ }
+
+ //*********************************************************************
+ /// Find content within the string
+ ///\param str The content to find
+ ///\param pos The position to start searching from.
+ //*********************************************************************
+ size_t rfind(const ibasic_string<T>& str, size_t position = npos) const
+ {
+ if ((str.size()) > size())
+ {
+ return npos;
+ }
+
+ if (position >= size())
+ {
+ position = size();
+ }
+
+ position = size() - position;
+
+ const_reverse_iterator iposition = std::search(rbegin() + position, rend(), str.rbegin(), str.rend());
+
+ if (iposition == rend())
+ {
+ return npos;
+ }
+ else
+ {
+ return size() - str.size() - std::distance(rbegin(), iposition);
+ }
+ }
+
+ //*********************************************************************
+ /// Find content within the string
+ ///\param str The content to find
+ ///\param pos The position to start searching from.
+ //*********************************************************************
+ size_t rfind(const_pointer s, size_t position = npos) const
+ {
+ size_t length = etl::strlen(s);
+
+ if (length > size())
+ {
+ return npos;
+ }
+
+ if (position >= size())
+ {
+ position = size();
+ }
+
+ position = size() - position;
+
+ const_reverse_iterator srbegin(s + length);
+ const_reverse_iterator srend(s);
+
+ const_reverse_iterator iposition = std::search(rbegin() + position, rend(), srbegin, srend);
+
+ if (iposition == rend())
+ {
+ return npos;
+ }
+ else
+ {
+ return size() - length - std::distance(rbegin(), iposition);
+ }
+ }
+
+ //*********************************************************************
+ /// Find content within the string
+ ///\param str The content to find
+ ///\param pos The position to start searching from.
+ //*********************************************************************
+ size_t rfind(const_pointer s, size_t position, size_t length) const
+ {
+ if (length > size())
+ {
+ return npos;
+ }
+
+ if (position >= size())
+ {
+ position = size();
+ }
+
+ position = size() - position;
+
+ const_reverse_iterator srbegin(s + length);
+ const_reverse_iterator srend(s);
+
+ const_reverse_iterator iposition = std::search(rbegin() + position, rend(), srbegin, srend);
+
+ if (iposition == rend())
+ {
+ return npos;
+ }
+ else
+ {
+ return size() - length - std::distance(rbegin(), iposition);
+ }
+ }
+
+ //*********************************************************************
+ /// Find character within the string
+ ///\param c The character to find
+ ///\param pos The position to start searching from.
+ //*********************************************************************
+ size_t rfind(T c, size_t position = npos) const
+ {
+ if (position >= size())
+ {
+ position = size();
+ }
+
+ position = size() - position;
+
+ const_reverse_iterator i = std::find(rbegin() + position, rend(), c);
+
+ if (i != rend())
+ {
+ return size() - std::distance(rbegin(), i) - 1;
+ }
+ else
+ {
+ return npos;
+ }
+ }
+
+ //*********************************************************************
+ /// Replace 'length' characters from 'position' with 'str'.
+ ///\param position The position to start from.
+ ///\param length The number of characters to replace.
+ ///\param str The string to replace it with.
+ //*********************************************************************
+ ibasic_string& replace(size_t position, size_t length, const ibasic_string& str)
+ {
+ ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds));
+
+ // Limit the length.
+ length = std::min(length, size() - position);
+
+ // Erase the bit we want to replace.
+ erase(position, length);
+
+ // Insert the new stuff.
+ insert(position, str);
+
+ return *this;
+ }
+
+ //*********************************************************************
+ /// Replace characters from 'first' to one before 'last' with 'str'.
+ ///\param first The position to start from.
+ ///\param last The one after the position to end at.
+ ///\param str The string to replace it with.
+ //*********************************************************************
+ ibasic_string& replace(const_iterator first, const_iterator last, const ibasic_string& str)
+ {
+ // Quick hack, as iterators are pointers.
+ iterator first_ = const_cast<iterator>(first);
+ iterator last_ = const_cast<iterator>(last);
+
+ // Erase the bit we want to replace.
+ erase(first_, last_);
+
+ // Insert the new stuff.
+ insert(first_, str.begin(), str.end());
+
+ return *this;
+ }
+
+ //*********************************************************************
+ /// Replace characters from 'position' of 'length' with 'str' from 'subpsotion' of 'sublength'.
+ //*********************************************************************
+ ibasic_string& replace(size_t position, size_t length, const ibasic_string& str, size_t subposition, size_t sublength)
+ {
+ ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds));
+ ETL_ASSERT(subposition <= str.size(), ETL_ERROR(string_out_of_bounds));
+
+ // Limit the lengths.
+ length = std::min(length, size() - position);
+ sublength = std::min(sublength, str.size() - subposition);
+
+ // Erase the bit we want to replace.
+ erase(position, length);
+
+ // Insert the new stuff.
+ insert(position, str, subposition, sublength);
+
+ return *this;
+ }
+
+ //*********************************************************************
+ /// Replace characters from 'position' of 'length' with pointed to string.
+ //*********************************************************************
+ ibasic_string& replace(size_t position, size_t length, const_pointer s)
+ {
+ ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds));
+
+ // Limit the length.
+ length = std::min(length, size() - position);
+
+ // Erase the bit we want to replace.
+ erase(position, length);
+
+ // Insert the new stuff.
+ insert(position, s, etl::strlen(s));
+
+ return *this;
+ }
+
+ //*********************************************************************
+ /// Replace characters from 'first' 'last' with pointed to string.
+ //*********************************************************************
+ ibasic_string& replace(const_iterator first, const_iterator last, const_pointer s)
+ {
+ // Quick hack, as iterators are pointers.
+ iterator first_ = const_cast<iterator>(first);
+ iterator last_ = const_cast<iterator>(last);
+
+ // Erase the bit we want to replace.
+ erase(first_, last_);
+
+ // Insert the new stuff.
+ insert(first_, s, s + etl::strlen(s));
+
+ return *this;
+ }
+
+ //*********************************************************************
+ /// Replace characters from 'position' of 'length' with 'n' characters from pointed to string.
+ //*********************************************************************
+ ibasic_string& replace(size_t position, size_t length, const_pointer s, size_t n)
+ {
+ ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds));
+
+ // Limit the length.
+ length = std::min(length, size() - position);
+
+ // Erase the bit we want to replace.
+ erase(position, length);
+
+ // Insert the new stuff.
+ insert(position, s, n);
+
+ return *this;
+ }
+
+ //*********************************************************************
+ /// Replace characters from 'first' to 'last' with 'n' characters from pointed to string.
+ //*********************************************************************
+ ibasic_string& replace(const_iterator first, const_iterator last, const_pointer s, size_t n)
+ {
+ // Quick hack, as iterators are pointers.
+ iterator first_ = const_cast<iterator>(first);
+ iterator last_ = const_cast<iterator>(last);
+
+ // Erase the bit we want to replace.
+ erase(first_, last_);
+
+ // Insert the new stuff.
+ insert(first_, s, s + n);
+
+ return *this;
+ }
+
+ //*********************************************************************
+ /// Replace characters from 'position' of 'length' with 'n' copies of 'c'.
+ //*********************************************************************
+ ibasic_string& replace(size_t position, size_t length, size_t n, value_type c)
+ {
+ ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds));
+
+ // Limit the length.
+ length = std::min(length, size() - position);
+
+ // Erase the bit we want to replace.
+ erase(position, length);
+
+ // Insert the new stuff.
+ insert(position, n, c);
+
+ return *this;
+ }
+
+ //*********************************************************************
+ /// Replace characters from 'first' of 'last' with 'n' copies of 'c'.
+ //*********************************************************************
+ ibasic_string& replace(const_iterator first, const_iterator last, size_t n, value_type c)
+ {
+ // Quick hack, as iterators are pointers.
+ iterator first_ = const_cast<iterator>(first);
+ iterator last_ = const_cast<iterator>(last);
+
+ // Erase the bit we want to replace.
+ erase(first_, last_);
+
+ // Insert the new stuff.
+ insert(first_, n, c);
+
+ return *this;
+ }
+
+ //*********************************************************************
+ /// Replace characters from 'first' of 'last' with characters from 'first_replace' to 'last_replace'.
+ //*********************************************************************
+ template <typename TIterator>
+ ibasic_string& replace(const_iterator first, const_iterator last, TIterator first_replace, TIterator last_replace)
+ {
+ // Quick hack, as iterators are pointers.
+ iterator first_ = const_cast<iterator>(first);
+ iterator last_ = const_cast<iterator>(last);
+
+ // Erase the bit we want to replace.
+ erase(first_, last_);
+
+ // Insert the new stuff.
+ insert(first_, first_replace, last_replace);
+
+ return *this;
+ }
+
+ //*************************************************************************
+ /// Compare with string.
+ //*************************************************************************
+ int compare(const ibasic_string& str) const
+ {
+ return compare(p_buffer,
+ p_buffer + size(),
+ str.p_buffer,
+ str.p_buffer + str.size());
+ }
+
+ //*************************************************************************
+ /// Compare position / length with string.
+ //*************************************************************************
+ int compare(size_t position, size_t length, const ibasic_string& str) const
+ {
+ ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds));
+
+ // Limit the length.
+ length = std::min(length, size() - position);
+
+ return compare(p_buffer + position,
+ p_buffer + position + length,
+ str.p_buffer,
+ str.p_buffer + str.size());
+ }
+
+ //*************************************************************************
+ /// Compare position / length with string / subposition / sublength.
+ //*************************************************************************
+ int compare(size_t position, size_t length, const ibasic_string& str, size_t subposition, size_t sublength) const
+ {
+ ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds));
+ ETL_ASSERT(subposition <= str.size(), ETL_ERROR(string_out_of_bounds));
+
+ // Limit the lengths.
+ length = std::min(length, size() - position);
+ sublength = std::min(sublength, str.size() - subposition);
+
+ return compare(p_buffer + position,
+ p_buffer + position + length,
+ str.p_buffer + subposition,
+ str.p_buffer + subposition + sublength);
+ }
+
+ //*************************************************************************
+ /// Compare with C string
+ //*************************************************************************
+ int compare(const value_type* s) const
+ {
+ return compare(p_buffer,
+ p_buffer+ size(),
+ s,
+ s + etl::strlen(s));
+ }
+
+ //*************************************************************************
+ /// Compare position / length with C string.
+ //*************************************************************************
+ int compare(size_t position, size_t length, const_pointer s) const
+ {
+ return compare(p_buffer + position,
+ p_buffer + position + length,
+ s,
+ s + etl::strlen(s));
+ }
+
+ //*************************************************************************
+ /// Compare position / length with C string / n.
+ //*************************************************************************
+ int compare(size_t position, size_t length, const_pointer s, size_t n) const
+ {
+ return compare(p_buffer + position,
+ p_buffer + position + length,
+ s,
+ s + n);;
+ }
+
+ //*********************************************************************
+ /// Find first of any of content within the string
+ ///\param str The content to find
+ ///\param pos The position to start searching from.
+ //*********************************************************************
+ size_t find_first_of(const ibasic_string<T>& str, size_t position = 0) const
+ {
+ return find_first_of(str.c_str(), position, str.size());
+ }
+
+ //*********************************************************************
+ /// Find first of any of content within the string
+ ///\param s Pointer to the content to find
+ ///\param pos The position to start searching from.
+ //*********************************************************************
+ size_t find_first_of(const_pointer s, size_t position = 0) const
+ {
+ return find_first_of(s, position, etl::strlen(s));
+ }
+
+ //*********************************************************************
+ /// Find first of any of content within the string
+ ///\param s Pointer to the content to find
+ ///\param pos The position to start searching from.
+ ///\param n The number of characters to search for.
+ //*********************************************************************
+ size_t find_first_of(const_pointer s, size_t position, size_t n) const
+ {
+ if (position < size())
+ {
+ for (size_t i = position; i < size(); ++i)
+ {
+ for (size_t j = 0; j < n; ++j)
+ {
+ if (p_buffer[i] == s[j])
+ {
+ return i;
+ }
+ }
+ }
+ }
+
+ return npos;
+ }
+
+ //*********************************************************************
+ /// Find first of character within the string
+ ///\param c The character to find
+ ///\param pos The position to start searching from.
+ //*********************************************************************
+ size_t find_first_of(value_type c, size_t position = 0) const
+ {
+ if (position < size())
+ {
+ for (size_t i = position; i < size(); ++i)
+ {
+ if (p_buffer[i] == c)
+ {
+ return i;
+ }
+ }
+ }
+
+ return npos;
+ }
+
+ //*********************************************************************
+ /// Find last of any of content within the string
+ ///\param str The content to find
+ ///\param pos The position to start searching from.
+ //*********************************************************************
+ size_t find_last_of(const ibasic_string<T>& str, size_t position = npos) const
+ {
+ return find_last_of(str.c_str(), position, str.size());
+ }
+
+ //*********************************************************************
+ /// Find last of any of content within the string
+ ///\param s Pointer to the content to find
+ ///\param pos The position to start searching from.
+ //*********************************************************************
+ size_t find_last_of(const_pointer s, size_t position = npos) const
+ {
+ return find_last_of(s, position, etl::strlen(s));
+ }
+
+ //*********************************************************************
+ /// Find last of any of content within the string
+ ///\param s Pointer to the content to find
+ ///\param pos The position to start searching from.
+ ///\param n The number of characters to search for.
+ //*********************************************************************
+ size_t find_last_of(const_pointer s, size_t position, size_t n) const
+ {
+ if (empty())
+ {
+ return npos;
+ }
+
+ position = std::min(position, size() - 1);
+
+ const_reverse_iterator it = rbegin() + size() - position - 1;
+
+ while (it != rend())
+ {
+ for (size_t j = 0; j < n; ++j)
+ {
+ if (p_buffer[position] == s[j])
+ {
+ return position;
+ }
+ }
+
+ ++it;
+ --position;
+ }
+
+ return npos;
+ }
+
+ //*********************************************************************
+ /// Find last of character within the string
+ ///\param c The character to find
+ ///\param pos The position to start searching from.
+ //*********************************************************************
+ size_t find_last_of(value_type c, size_t position = npos) const
+ {
+ if (empty())
+ {
+ return npos;
+ }
+
+ position = std::min(position, size() - 1);
+
+ const_reverse_iterator it = rbegin() + size() - position - 1;
+
+ while (it != rend())
+ {
+ if (p_buffer[position] == c)
+ {
+ return position;
+ }
+
+ ++it;
+ --position;
+ }
+
+ return npos;
+ }
+
+ //*********************************************************************
+ /// Find first not of any of content within the string
+ ///\param str The content to find
+ ///\param pos The position to start searching from.
+ //*********************************************************************
+ size_t find_first_not_of(const ibasic_string<T>& str, size_t position = 0) const
+ {
+ return find_first_not_of(str.c_str(), position, str.size());
+ }
+
+ //*********************************************************************
+ /// Find first not of any of content within the string
+ ///\param s Pointer to the content to not find
+ ///\param pos The position to start searching from.
+ //*********************************************************************
+ size_t find_first_not_of(const_pointer s, size_t position = 0) const
+ {
+ return find_first_not_of(s, position, etl::strlen(s));
+ }
+
+ //*********************************************************************
+ /// Find first not of any of content within the string
+ ///\param s Pointer to the content to not find
+ ///\param pos The position to start searching from.
+ ///\param n The number of characters to search for.
+ //*********************************************************************
+ size_t find_first_not_of(const_pointer s, size_t position, size_t n) const
+ {
+ if (position < size())
+ {
+ for (size_t i = position; i < size(); ++i)
+ {
+ bool found = false;
+
+ for (size_t j = 0; j < n; ++j)
+ {
+ if (p_buffer[i] == s[j])
+ {
+ found = true;
+ }
+ }
+
+ if (!found)
+ {
+ return i;
+ }
+ }
+ }
+
+ return npos;
+ }
+
+ //*********************************************************************
+ /// Find first not of character within the string
+ ///\param c The character to not find
+ ///\param pos The position to start searching from.
+ //*********************************************************************
+ size_t find_first_not_of(value_type c, size_t position = 0) const
+ {
+ if (position < size())
+ {
+ for (size_t i = position; i < size(); ++i)
+ {
+ if (p_buffer[i] != c)
+ {
+ return i;
+ }
+ }
+ }
+
+ return npos;
+ }
+
+ //*********************************************************************
+ /// Find last not of any of content within the string
+ ///\param str The content to find
+ ///\param pos The position to start searching from.
+ //*********************************************************************
+ size_t find_last_not_of(const ibasic_string<T>& str, size_t position = npos) const
+ {
+ return find_last_not_of(str.c_str(), position, str.size());
+ }
+
+ //*********************************************************************
+ /// Find last not of any of content within the string
+ ///\param s The pointer to the content to find
+ ///\param pos The position to start searching from.
+ //*********************************************************************
+ size_t find_last_not_of(const_pointer s, size_t position = npos) const
+ {
+ return find_last_not_of(s, position, etl::strlen(s));
+ }
+
+ //*********************************************************************
+ /// Find last not of any of content within the string
+ ///\param s The pointer to the content to find
+ ///\param pos The position to start searching from.
+ ///\param n The number of characters to use.
+ //*********************************************************************
+ size_t find_last_not_of(const_pointer s, size_t position, size_t n) const
+ {
+ if (empty())
+ {
+ return npos;
+ }
+
+ position = std::min(position, size() - 1);
+
+ const_reverse_iterator it = rbegin() + size() - position - 1;
+
+ while (it != rend())
+ {
+ bool found = false;
+
+ for (size_t j = 0; j < n; ++j)
+ {
+ if (p_buffer[position] == s[j])
+ {
+ found = true;
+ }
+ }
+
+ if (!found)
+ {
+ return position;
+ }
+
+ ++it;
+ --position;
+ }
+
+ return npos;
+ }
+
+ //*********************************************************************
+ //
+ //*********************************************************************
+ size_t find_last_not_of(value_type c, size_t position = npos) const
+ {
+ if (empty())
+ {
+ return npos;
+ }
+
+ position = std::min(position, size() - 1);
+
+ const_reverse_iterator it = rbegin() + size() - position - 1;
+
+ while (it != rend())
+ {
+ if (p_buffer[position] != c)
+ {
+ return position;
+ }
+
+ ++it;
+ --position;
+ }
+
+ return npos;
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ ibasic_string& operator = (const ibasic_string& rhs)
+ {
+ if (&rhs != this)
+ {
+ assign(rhs.cbegin(), rhs.cend());
+ }
+
+ return *this;
+ }
+
+ //*************************************************************************
+ /// += operator.
+ //*************************************************************************
+ ibasic_string& operator += (const ibasic_string& rhs)
+ {
+ if (&rhs != this)
+ {
+ append(rhs);
+ }
+
+ return *this;
+ }
+
+ //*************************************************************************
+ /// += operator.
+ //*************************************************************************
+ ibasic_string& operator += (const T* rhs)
+ {
+ append(rhs);
+
+ return *this;
+ }
+
+ //*************************************************************************
+ /// += operator.
+ //*************************************************************************
+ ibasic_string& operator += (T rhs)
+ {
+ append(size_t(1), rhs);
+
+ return *this;
+ }
+
+ protected:
+
+ //*********************************************************************
+ /// Constructor.
+ //*********************************************************************
+ ibasic_string(T* p_buffer, size_t MAX_SIZE)
+ : string_base(MAX_SIZE),
+ p_buffer(p_buffer)
+ {
+ }
+
+ //*********************************************************************
+ /// Initialise the string.
+ //*********************************************************************
+ void initialise()
+ {
+ current_size = 0;
+ p_buffer[0] = 0;
+ }
+
+ private:
+
+ //*************************************************************************
+ /// Compare helper function
+ //*************************************************************************
+ int compare(const_pointer first1, const_pointer last1, const_pointer first2, const_pointer last2) const
+ {
+ while ((first1 != last1) && (first2 != last2))
+ {
+ if (*first1 < *first2)
+ {
+ // Compared character is lower.
+ return -1;
+ }
+ else if (*first1 > *first2)
+ {
+ // Compared character is higher.
+ return 1;
+ }
+
+ ++first1;
+ ++first2;
+ }
+
+ // We reached the end of one or both of the strings.
+ if ((first1 == last1) && (first2 == last2))
+ {
+ // Same length.
+ return 0;
+ }
+ else if (first1 == last1)
+ {
+ // Compared string is shorter.
+ return -1;
+ }
+ else
+ {
+ // Compared string is longer.
+ return 1;
+ }
+ }
+
+ // Disable copy construction.
+ ibasic_string(const ibasic_string&);
+
+ T* p_buffer;
+ };
+
+ //***************************************************************************
+ /// Equal operator.
+ ///\param lhs Reference to the first string.
+ ///\param rhs Reference to the second string.
+ ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
+ ///\ingroup string
+ //***************************************************************************
+ template <typename T>
+ bool operator ==(const etl::ibasic_string<T>& lhs, const etl::ibasic_string<T>& rhs)
+ {
+ return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin());
+ }
+
+ //***************************************************************************
+ /// Equal operator.
+ ///\param lhs Reference to the first string.
+ ///\param rhs Reference to the second string.
+ ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
+ ///\ingroup string
+ //***************************************************************************
+ template <typename T>
+ bool operator ==(const etl::ibasic_string<T>& lhs, const T* rhs)
+ {
+ return (lhs.size() == etl::strlen(rhs)) && std::equal(lhs.begin(), lhs.end(), rhs);
+ }
+
+ //***************************************************************************
+ /// Equal operator.
+ ///\param lhs Reference to the first string.
+ ///\param rhs Reference to the second string.
+ ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
+ ///\ingroup string
+ //***************************************************************************
+ template <typename T>
+ bool operator ==(const T* lhs, const etl::ibasic_string<T>& rhs)
+ {
+ return (rhs.size() == etl::strlen(lhs)) && std::equal(rhs.begin(), rhs.end(), lhs);
+ }
+
+
+ //***************************************************************************
+ /// Not equal operator.
+ ///\param lhs Reference to the first string.
+ ///\param rhs Reference to the second string.
+ ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
+ ///\ingroup string
+ //***************************************************************************
+ template <typename T>
+ bool operator !=(const etl::ibasic_string<T>& lhs, const etl::ibasic_string<T>& rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+ //***************************************************************************
+ /// Not equal operator.
+ ///\param lhs Reference to the first string.
+ ///\param rhs Reference to the second string.
+ ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
+ ///\ingroup string
+ //***************************************************************************
+ template <typename T>
+ bool operator !=(const etl::ibasic_string<T>& lhs, const T* rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+ //***************************************************************************
+ /// Not equal operator.
+ ///\param lhs Reference to the first string.
+ ///\param rhs Reference to the second string.
+ ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
+ ///\ingroup string
+ //***************************************************************************
+ template <typename T>
+ bool operator !=(const T* lhs, const etl::ibasic_string<T>& rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+
+ //***************************************************************************
+ /// Less than operator.
+ ///\param lhs Reference to the first string.
+ ///\param rhs Reference to the second string.
+ ///\return <b>true</b> if the first string is lexicographically less than the second, otherwise <b>false</b>
+ ///\ingroup string
+ //***************************************************************************
+ template <typename T>
+ bool operator <(const etl::ibasic_string<T>& lhs, const etl::ibasic_string<T>& rhs)
+ {
+ return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
+ }
+
+ //***************************************************************************
+ /// Less than operator.
+ ///\param lhs Reference to the first string.
+ ///\param rhs Reference to the second string.
+ ///\return <b>true</b> if the first string is lexicographically less than the second, otherwise <b>false</b>
+ ///\ingroup string
+ //***************************************************************************
+ template <typename T>
+ bool operator <(const etl::ibasic_string<T>& lhs, const T* rhs)
+ {
+ return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs, rhs + etl::strlen(rhs));
+ }
+
+ //***************************************************************************
+ /// Less than operator.
+ ///\param lhs Reference to the first string.
+ ///\param rhs Reference to the second string.
+ ///\return <b>true</b> if the first string is lexicographically less than the second, otherwise <b>false</b>
+ ///\ingroup string
+ //***************************************************************************
+ template <typename T>
+ bool operator <(const T* lhs, const etl::ibasic_string<T>& rhs)
+ {
+ return std::lexicographical_compare(lhs, lhs + etl::strlen(lhs), rhs.begin(), rhs.end());
+ }
+
+
+ //***************************************************************************
+ /// Greater than operator.
+ ///\param lhs Reference to the first string.
+ ///\param rhs Reference to the second string.
+ ///\return <b>true</b> if the first string is lexicographically greater than the second, otherwise <b>false</b>
+ ///\ingroup string
+ //***************************************************************************
+ template <typename T>
+ bool operator >(const etl::ibasic_string<T>& lhs, const etl::ibasic_string<T>& rhs)
+ {
+ return (rhs < lhs);
+ }
+
+ //***************************************************************************
+ /// Greater than operator.
+ ///\param lhs Reference to the first string.
+ ///\param rhs Reference to the second string.
+ ///\return <b>true</b> if the first string is lexicographically greater than the second, otherwise <b>false</b>
+ ///\ingroup string
+ //***************************************************************************
+ template <typename T>
+ bool operator >(const etl::ibasic_string<T>& lhs, const T* rhs)
+ {
+ return (rhs < lhs);
+ }
+
+ //***************************************************************************
+ /// Greater than operator.
+ ///\param lhs Reference to the first string.
+ ///\param rhs Reference to the second string.
+ ///\return <b>true</b> if the first string is lexicographically greater than the second, otherwise <b>false</b>
+ ///\ingroup string
+ //***************************************************************************
+ template <typename T>
+ bool operator >(const T* lhs, const etl::ibasic_string<T>& rhs)
+ {
+ return (rhs < lhs);
+ }
+
+
+ //***************************************************************************
+ /// Less than or equal operator.
+ ///\param lhs Reference to the first string.
+ ///\param rhs Reference to the second string.
+ ///\return <b>true</b> if the first string is lexicographically less than or equal to the second, otherwise <b>false</b>
+ ///\ingroup string
+ //***************************************************************************
+ template <typename T>
+ bool operator <=(const etl::ibasic_string<T>& lhs, const etl::ibasic_string<T>& rhs)
+ {
+ return !(lhs > rhs);
+ }
+
+ //***************************************************************************
+ /// Less than or equal operator.
+ ///\param lhs Reference to the first string.
+ ///\param rhs Reference to the second string.
+ ///\return <b>true</b> if the first string is lexicographically less than or equal to the second, otherwise <b>false</b>
+ ///\ingroup string
+ //***************************************************************************
+ template <typename T>
+ bool operator <=(const etl::ibasic_string<T>& lhs, const T* rhs)
+ {
+ return !(lhs > rhs);
+ }
+
+ //***************************************************************************
+ /// Less than or equal operator.
+ ///\param lhs Reference to the first string.
+ ///\param rhs Reference to the second string.
+ ///\return <b>true</b> if the first string is lexicographically less than or equal to the second, otherwise <b>false</b>
+ ///\ingroup string
+ //***************************************************************************
+ template <typename T>
+ bool operator <=(const T* lhs, const etl::ibasic_string<T>& rhs)
+ {
+ return !(lhs > rhs);
+ }
+
+
+ //***************************************************************************
+ /// Greater than or equal operator.
+ ///\param lhs Reference to the first string.
+ ///\param rhs Reference to the second string.
+ ///\return <b>true</b> if the first string is lexicographically greater than or equal to the second, otherwise <b>false</b>
+ ///\ingroup string
+ //***************************************************************************
+ template <typename T>
+ bool operator >=(const etl::ibasic_string<T>& lhs, const etl::ibasic_string<T>& rhs)
+ {
+ return !(lhs < rhs);
+ }
+
+ //***************************************************************************
+ /// Greater than or equal operator.
+ ///\param lhs Reference to the first string.
+ ///\param rhs Reference to the second string.
+ ///\return <b>true</b> if the first string is lexicographically greater than or equal to the second, otherwise <b>false</b>
+ ///\ingroup string
+ //***************************************************************************
+ template <typename T>
+ bool operator >=(const etl::ibasic_string<T>& lhs, const T* rhs)
+ {
+ return !(lhs < rhs);
+ }
+
+ //***************************************************************************
+ /// Greater than or equal operator.
+ ///\param lhs Reference to the first string.
+ ///\param rhs Reference to the second string.
+ ///\return <b>true</b> if the first string is lexicographically greater than or equal to the second, otherwise <b>false</b>
+ ///\ingroup string
+ //***************************************************************************
+ template <typename T>
+ bool operator >=(const T* lhs, const etl::ibasic_string<T>& rhs)
+ {
+ return !(lhs < rhs);
+ }
+}
+
+#ifdef ETL_COMPILER_MICROSOFT
+ #define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#undef __ETL_IN_ISTRING_H__
+#endif
diff --git a/lib/etl/ibitset.h b/lib/etl/ibitset.h
new file mode 100644
index 0000000..ee2747f
--- /dev/null
+++ b/lib/etl/ibitset.h
@@ -0,0 +1,712 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_IBITSET__
+#define __ETL_IBITSET__
+
+#include <algorithm>
+#include <stdint.h>
+#include <string.h>
+
+#include "exception.h"
+#include "integral_limits.h"
+#include "binary.h"
+#include "algorithm.h"
+#include "platform.h"
+
+#ifdef ETL_COMPILER_MICROSOFT
+#undef min
+#endif
+
+namespace etl
+{
+ //***************************************************************************
+ /// Exception base for bitset
+ ///\ingroup bitset
+ //***************************************************************************
+ class bitset_exception : public etl::exception
+ {
+ public:
+
+ bitset_exception(string_type what, string_type file_name, numeric_type line_number)
+ : exception(what, file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// Bitset nullptr exception.
+ ///\ingroup bitset
+ //***************************************************************************
+ class bitset_nullptr : public bitset_exception
+ {
+ public:
+
+ bitset_nullptr(string_type file_name, numeric_type line_number)
+ : bitset_exception("bitset: nullptr", file_name, line_number)
+ {
+ }
+ };
+
+ //*************************************************************************
+ /// The base class for etl::bitset
+ ///\ingroup bitset
+ //*************************************************************************
+ class ibitset
+ {
+ protected:
+
+ // The type used for each element in the array.
+#if !defined(ETL_BITSET_ELEMENT_TYPE)
+ typedef uint8_t element_t;
+#else
+ typedef ETL_BITSET_ELEMENT_TYPE element_t;
+#endif
+
+ public:
+
+ static const element_t ALL_SET = etl::integral_limits<element_t>::max;
+ static const element_t ALL_CLEAR = 0;
+
+ static const size_t BITS_PER_ELEMENT = etl::integral_limits<element_t>::bits;
+
+ enum
+ {
+ npos = etl::integral_limits<size_t>::max
+ };
+
+ //*************************************************************************
+ /// The reference type returned.
+ //*************************************************************************
+ class bit_reference
+ {
+ public:
+
+ friend class ibitset;
+
+ //*******************************
+ /// Conversion operator.
+ //*******************************
+ operator bool() const
+ {
+ return p_bitset->test(position);
+ }
+
+ //*******************************
+ /// Assignment operator.
+ //*******************************
+ bit_reference& operator = (bool b)
+ {
+ p_bitset->set(position, b);
+ return *this;
+ }
+
+ //*******************************
+ /// Assignment operator.
+ //*******************************
+ bit_reference& operator = (const bit_reference& r)
+ {
+ p_bitset->set(position, bool(r));
+ return *this;
+ }
+
+ //*******************************
+ /// Flip the bit.
+ //*******************************
+ bit_reference& flip()
+ {
+ p_bitset->flip(position);
+ return *this;
+ }
+
+ //*******************************
+ /// Return the logical inverse of the bit.
+ //*******************************
+ bool operator~() const
+ {
+ return !p_bitset->test(position);
+ }
+
+ private:
+
+ //*******************************
+ /// Default constructor.
+ //*******************************
+ bit_reference()
+ : p_bitset(nullptr),
+ position(0)
+ {
+ }
+
+ //*******************************
+ /// Constructor.
+ //*******************************
+ bit_reference(ibitset& r_bitset, size_t position)
+ : p_bitset(&r_bitset),
+ position(position)
+ {
+ }
+
+ ibitset* p_bitset; ///< The bitset.
+ size_t position; ///< The position in the bitset.
+ };
+
+ //*************************************************************************
+ /// The size of the bitset.
+ //*************************************************************************
+ size_t size() const
+ {
+ return NBITS;
+ }
+
+ //*************************************************************************
+ /// Count the number of bits set.
+ //*************************************************************************
+ size_t count() const
+ {
+ size_t n = 0;
+
+ for (size_t i = 0; i < SIZE; ++i)
+ {
+ n += etl::count_bits(pdata[i]);
+ }
+
+ return n;
+ }
+
+ //*************************************************************************
+ /// Tests a bit at a position.
+ /// Positions greater than the number of configured bits will return <b>false</b>.
+ //*************************************************************************
+ bool test(size_t position) const
+ {
+ size_t index;
+ element_t mask;
+
+ if (SIZE == 1)
+ {
+ index = 0;
+ mask = element_t(1) << position;
+ }
+ else
+ {
+ index = position >> etl::log2<BITS_PER_ELEMENT>::value;
+ mask = element_t(1) << (position & (BITS_PER_ELEMENT - 1));
+ }
+
+ return (pdata[index] & mask) != 0;
+ }
+
+ //*************************************************************************
+ /// Set the bit at the position.
+ //*************************************************************************
+ ibitset& set()
+ {
+ for (size_t i = 0; i < SIZE; ++i)
+ {
+ pdata[i] = ALL_SET;
+ }
+
+ pdata[SIZE - 1] &= TOP_MASK;
+
+ return *this;
+ }
+
+ //*************************************************************************
+ /// Set the bit at the position.
+ //*************************************************************************
+ ibitset& set(size_t position, bool value = true)
+ {
+ size_t index;
+ element_t bit;
+
+ if (SIZE == 1)
+ {
+ index = 0;
+ bit = element_t(1) << position;
+ }
+ else
+ {
+ index = position >> etl::log2<BITS_PER_ELEMENT>::value;
+ bit = element_t(1) << (position & (BITS_PER_ELEMENT - 1));
+ }
+
+ if (value)
+ {
+ pdata[index] |= bit;
+ }
+ else
+ {
+ pdata[index] &= ~bit;
+ }
+
+ return *this;
+ }
+
+ //*************************************************************************
+ /// Set from a string.
+ //*************************************************************************
+ ibitset& set(const char* text)
+ {
+ reset();
+
+ size_t i = std::min(NBITS, strlen(text));
+
+ while (i > 0)
+ {
+ set(--i, *text++ == '1');
+ }
+
+ return *this;
+ }
+
+ //*************************************************************************
+ /// Resets the bitset.
+ //*************************************************************************
+ ibitset& reset()
+ {
+ for (size_t i = 0; i < SIZE; ++i)
+ {
+ pdata[i] = ALL_CLEAR;
+ }
+
+ return *this;
+ }
+
+ //*************************************************************************
+ /// Reset the bit at the position.
+ //*************************************************************************
+ ibitset& reset(size_t position)
+ {
+ size_t index;
+ element_t bit;
+
+ if (SIZE == 1)
+ {
+ index = 0;
+ bit = element_t(1) << position;
+ }
+ else
+ {
+ index = position >> etl::log2<BITS_PER_ELEMENT>::value;
+ bit = element_t(1) << (position & (BITS_PER_ELEMENT - 1));
+ }
+
+ pdata[index] &= ~bit;
+
+ return *this;
+ }
+
+ //*************************************************************************
+ /// Flip all of the bits.
+ //*************************************************************************
+ ibitset& flip()
+ {
+ for (size_t i = 0; i < SIZE; ++i)
+ {
+ pdata[i] = ~pdata[i];
+ }
+
+ pdata[SIZE - 1] &= TOP_MASK;
+
+ return *this;
+ }
+
+ //*************************************************************************
+ /// Flip the bit at the position.
+ //*************************************************************************
+ ibitset& flip(size_t position)
+ {
+ if (position < NBITS)
+ {
+ size_t index;
+ element_t bit;
+
+ if (SIZE == 1)
+ {
+ index = 0;
+ bit = element_t(1) << position;
+ }
+ else
+ {
+ index = position >> log2<BITS_PER_ELEMENT>::value;
+ bit = element_t(1) << (position & (BITS_PER_ELEMENT - 1));
+ }
+
+ pdata[index] ^= bit;
+ }
+
+ return *this;
+ }
+
+ //*************************************************************************
+ // Are all the bits sets?
+ //*************************************************************************
+ bool all() const
+ {
+ // All but the last.
+ for (size_t i = 0; i < (SIZE - 1); ++i)
+ {
+ if (pdata[i] != ALL_SET)
+ {
+ return false;
+ }
+ }
+
+ // The last.
+ if (pdata[SIZE - 1] != (ALL_SET & TOP_MASK))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ //*************************************************************************
+ /// Are any of the bits set?
+ //*************************************************************************
+ bool any() const
+ {
+ return !none();
+ }
+
+ //*************************************************************************
+ /// Are none of the bits set?
+ //*************************************************************************
+ bool none() const
+ {
+ for (size_t i = 0; i < SIZE; ++i)
+ {
+ if (pdata[i] != 0)
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ //*************************************************************************
+ /// Finds the first bit in the specified state.
+ ///\param state The state to search for.
+ ///\returns The position of the bit or SIZE if none were found.
+ //*************************************************************************
+ size_t find_first(bool state) const
+ {
+ return find_next(state, 0);
+ }
+
+ //*************************************************************************
+ /// Finds the next bit in the specified state.
+ ///\param state The state to search for.
+ ///\param position The position to start from.
+ ///\returns The position of the bit or SIZE if none were found.
+ //*************************************************************************
+ size_t find_next(bool state, size_t position) const
+ {
+ // Where to start.
+ size_t index;
+ size_t bit;
+
+ if (SIZE == 1)
+ {
+ index = 0;
+ bit = position;
+ }
+ else
+ {
+ index = position >> log2<BITS_PER_ELEMENT>::value;
+ bit = position & (BITS_PER_ELEMENT - 1);
+ }
+
+ element_t mask = 1 << bit;
+
+ // For each element in the bitset...
+ while (index < SIZE)
+ {
+ element_t value = pdata[index];
+
+ // Needs checking?
+ if (( state && (value != ALL_CLEAR)) ||
+ (!state && (value != ALL_SET)))
+ {
+ // For each bit in the element...
+ while ((bit < BITS_PER_ELEMENT) && (position < NBITS))
+ {
+ // Equal to the required state?
+ if (((value & mask) != 0) == state)
+ {
+ return position;
+ }
+
+ // Move on to the next bit.
+ mask <<= 1;
+ ++position;
+ ++bit;
+ }
+ }
+ else
+ {
+ position += BITS_PER_ELEMENT;
+ }
+
+ // Start at the beginning for all other elements.
+ bit = 0;
+ mask = 1;
+
+ ++index;
+ }
+
+ return ibitset::npos;
+ }
+
+ //*************************************************************************
+ /// Read [] operator.
+ //*************************************************************************
+ bool operator[] (size_t position) const
+ {
+ return test(position);
+ }
+
+ //*************************************************************************
+ /// Write [] operator.
+ //*************************************************************************
+ bit_reference operator [] (size_t position)
+ {
+ return bit_reference(*this, position);
+ }
+
+ //*************************************************************************
+ /// operator &=
+ //*************************************************************************
+ ibitset& operator &=(const ibitset& other)
+ {
+ for (size_t i = 0; i < SIZE; ++i)
+ {
+ pdata[i] &= other.pdata[i];
+ }
+
+ return *this;
+ }
+
+ //*************************************************************************
+ /// operator |=
+ //*************************************************************************
+ ibitset& operator |=(const ibitset& other)
+ {
+ for (size_t i = 0; i < SIZE; ++i)
+ {
+ pdata[i] |= other.pdata[i];
+ }
+
+ return *this;
+ }
+
+ //*************************************************************************
+ /// operator ^=
+ //*************************************************************************
+ ibitset& operator ^=(const ibitset& other)
+ {
+ for (size_t i = 0; i < SIZE; ++i)
+ {
+ pdata[i] ^= other.pdata[i];
+ }
+
+ return *this;
+ }
+
+ //*************************************************************************
+ /// operator <<=
+ //*************************************************************************
+ ibitset& operator<<=(size_t shift)
+ {
+ if (SIZE == 1)
+ {
+ pdata[0] <<= shift;
+ }
+ else
+ {
+ size_t source = NBITS - shift - 1;
+ size_t destination = NBITS - 1;
+
+ for (size_t i = 0; i < (NBITS - shift); ++i)
+ {
+ set(destination--, test(source--));
+ }
+
+ for (size_t i = 0; i < shift; ++i)
+ {
+ reset(destination--);
+ }
+ }
+
+ return *this;
+ }
+
+ //*************************************************************************
+ /// operator >>=
+ //*************************************************************************
+ ibitset& operator>>=(size_t shift)
+ {
+ if (SIZE == 1)
+ {
+ pdata[0] >>= shift;
+ }
+ else
+ {
+ size_t source = shift;
+ size_t destination = 0;
+
+ for (size_t i = 0; i < (NBITS - shift); ++i)
+ {
+ set(destination++, test(source++));
+ }
+
+ for (size_t i = 0; i < shift; ++i)
+ {
+ reset(destination++);
+ }
+ }
+
+ return *this;
+ }
+
+ //*************************************************************************
+ /// operator =
+ //*************************************************************************
+ ibitset& operator =(const ibitset& other)
+ {
+ if (this != &other)
+ {
+ etl::copy_n(other.pdata, SIZE, pdata);
+ }
+
+ return *this;
+ }
+
+ //*************************************************************************
+ /// swap
+ //*************************************************************************
+ void swap(ibitset& other)
+ {
+ std::swap_ranges(pdata, pdata + SIZE, other.pdata);
+ }
+
+ protected:
+
+ //*************************************************************************
+ /// Initialise from an unsigned long long.
+ //*************************************************************************
+ ibitset& initialise(unsigned long long value)
+ {
+ reset();
+
+ const size_t SHIFT = (integral_limits<unsigned long long>::bits <= (int)BITS_PER_ELEMENT) ? 0 : BITS_PER_ELEMENT;
+
+ // Can we do it in one hit?
+ if (SHIFT == 0)
+ {
+ pdata[0] = element_t(value);
+ }
+ else
+ {
+ size_t i = 0;
+
+ while ((value != 0) && (i < SIZE))
+ {
+ pdata[i++] = value & ALL_SET;
+ value = value >> SHIFT;
+ }
+ }
+
+ pdata[SIZE - 1] &= TOP_MASK;
+
+ return *this;
+ }
+
+ //*************************************************************************
+ /// Invert
+ //*************************************************************************
+ void invert()
+ {
+ for (size_t i = 0; i < SIZE; ++i)
+ {
+ pdata[i] = ~pdata[i];
+ }
+ }
+
+ //*************************************************************************
+ /// Gets a reference to the specified bit.
+ //*************************************************************************
+ bit_reference get_bit_reference(size_t position)
+ {
+ return bit_reference(*this, position);
+ }
+
+ //*************************************************************************
+ /// Constructor.
+ //*************************************************************************
+ ibitset(size_t nbits, size_t size, element_t* pdata)
+ : NBITS(nbits),
+ SIZE(size),
+ pdata(pdata)
+ {
+ size_t allocated_bits = SIZE * BITS_PER_ELEMENT;
+ size_t top_mask_shift = ((BITS_PER_ELEMENT - (allocated_bits - NBITS)) % BITS_PER_ELEMENT);
+ TOP_MASK = element_t(top_mask_shift == 0 ? ALL_SET : ~(ALL_SET << top_mask_shift));
+ }
+
+ //*************************************************************************
+ /// Compare bitsets.
+ //*************************************************************************
+ static bool is_equal(const ibitset& lhs, const ibitset&rhs)
+ {
+ return std::equal(lhs.pdata, lhs.pdata + lhs.SIZE, rhs.pdata);
+ }
+
+ element_t TOP_MASK;
+
+ private:
+
+ // Disable copy construction.
+ ibitset(const ibitset&);
+
+ const size_t NBITS;
+ const size_t SIZE;
+ element_t* pdata;
+ };
+}
+
+
+#ifdef ETL_COMPILER_MICROSOFT
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#endif
diff --git a/lib/etl/ideque.h b/lib/etl/ideque.h
new file mode 100644
index 0000000..6c23518
--- /dev/null
+++ b/lib/etl/ideque.h
@@ -0,0 +1,1465 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_IDEQUE__
+#define __ETL_IDEQUE__
+#define __ETL_IN_IDEQUE_H__
+
+#include <stddef.h>
+#include <iterator>
+
+#include "algorithm.h"
+#include "type_traits.h"
+#include "private/deque_base.h"
+#include "parameter_type.h"
+#include "error_handler.h"
+
+namespace etl
+{
+ //***************************************************************************
+ /// The base class for all etl::deque classes.
+ ///\tparam T The type of values this deque should hold.
+ ///\ingroup deque
+ //***************************************************************************
+ template <typename T>
+ class ideque : public deque_base
+ {
+ public:
+
+ typedef T value_type;
+ typedef size_t size_type;
+ typedef T& reference;
+ typedef const T& const_reference;
+ typedef T* pointer;
+ typedef const T* const_pointer;
+ typedef typename std::iterator_traits<pointer>::difference_type difference_type;
+
+ protected:
+
+ typedef typename parameter_type<T>::type parameter_t;
+
+ //*************************************************************************
+ /// Test for an iterator.
+ //*************************************************************************
+ template <typename TIterator>
+ struct is_iterator : public etl::integral_constant<bool, !etl::is_integral<TIterator>::value && !etl::is_floating_point<TIterator>::value>
+ {
+ };
+
+ public:
+
+ //*************************************************************************
+ /// Iterator
+ //*************************************************************************
+ struct iterator : public std::iterator<std::random_access_iterator_tag, T>
+ {
+ friend class ideque;
+
+ //***************************************************
+ iterator()
+ : index(0),
+ p_deque(0),
+ p_buffer(0)
+ {
+ }
+
+ //***************************************************
+ iterator(const iterator& other)
+ : index(other.index),
+ p_deque(other.p_deque),
+ p_buffer(other.p_buffer)
+ {
+ }
+
+ //***************************************************
+ iterator& operator ++()
+ {
+ index = (static_cast<size_t>(index) == p_deque->BUFFER_SIZE - 1) ? 0 : index + 1;
+
+ return *this;
+ }
+
+ //***************************************************
+ iterator operator ++(int)
+ {
+ iterator previous(*this);
+ index = (static_cast<size_t>(index) == p_deque->BUFFER_SIZE - 1) ? 0 : index + 1;
+
+ return previous;
+ }
+
+ //***************************************************
+ iterator& operator +=(difference_type offset)
+ {
+ if (offset > 0)
+ {
+ index += offset;
+ index = (static_cast<size_t>(index) > p_deque->BUFFER_SIZE - 1) ? index - p_deque->BUFFER_SIZE : index;
+ }
+ else if (offset < 0)
+ {
+ operator -= (-offset);
+ }
+
+ return *this;
+ }
+
+ //***************************************************
+ iterator& operator -=(difference_type offset)
+ {
+ if (offset > 0)
+ {
+ index -= offset;
+ index = (index < 0) ? index + p_deque->BUFFER_SIZE : index;
+ }
+ else if (offset < 0)
+ {
+ operator += (-offset);
+ }
+
+ return *this;
+ }
+
+ //***************************************************
+ iterator& operator --()
+ {
+ index = (index == 0) ? p_deque->BUFFER_SIZE - 1 : index - 1;
+
+ return *this;
+ }
+
+ //***************************************************
+ iterator operator --(int)
+ {
+ iterator previous(*this);
+ index = (index == 0) ? p_deque->BUFFER_SIZE - 1 : index - 1;
+
+ return previous;
+ }
+
+ //***************************************************
+ reference operator *()
+ {
+ return p_buffer[index];
+ }
+
+ //***************************************************
+ const_reference operator *() const
+ {
+ return p_buffer[index];
+ }
+
+ //***************************************************
+ pointer operator ->()
+ {
+ return &p_buffer[index];
+ }
+
+ //***************************************************
+ const_pointer operator ->() const
+ {
+ return &p_buffer[index];
+ }
+
+ //***************************************************
+ bool operator <(const iterator& other) const
+ {
+ return ideque::distance(*this, other) > 0;
+ }
+
+ //***************************************************
+ friend iterator operator +(const iterator& lhs, difference_type offset)
+ {
+ iterator result(lhs);
+ result += offset;
+ return result;
+ }
+
+ //***************************************************
+ friend iterator operator -(const iterator& lhs, difference_type offset)
+ {
+ iterator result(lhs);
+ result -= offset;
+ return result;
+ }
+
+ //***************************************************
+ friend bool operator == (const iterator& lhs, const iterator& rhs)
+ {
+ return lhs.index == rhs.index;
+ }
+
+ //***************************************************
+ friend bool operator != (const iterator& lhs, const iterator& rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+ //***************************************************
+ difference_type get_index() const
+ {
+ return index;
+ }
+
+ //***************************************************
+ ideque& get_deque() const
+ {
+ return *p_deque;
+ }
+
+ //***************************************************
+ pointer get_buffer() const
+ {
+ return p_buffer;
+ }
+
+ //***************************************************
+ void swap(iterator& other)
+ {
+ std::swap(index, other.index);
+ }
+
+ private:
+
+ //***************************************************
+ iterator(difference_type index, ideque& the_deque, pointer p_buffer)
+ : index(index),
+ p_deque(&the_deque),
+ p_buffer(p_buffer)
+ {
+ }
+
+ difference_type index;
+ ideque* p_deque;
+ pointer p_buffer;
+ };
+
+ //*************************************************************************
+ /// Const Iterator
+ //*************************************************************************
+ struct const_iterator : public std::iterator<std::random_access_iterator_tag, const T>
+ {
+ friend class ideque;
+
+ //***************************************************
+ const_iterator()
+ : index(0),
+ p_deque(0),
+ p_buffer(0)
+ {
+ }
+
+ //***************************************************
+ const_iterator(const const_iterator& other)
+ : index(other.index),
+ p_deque(other.p_deque),
+ p_buffer(other.p_buffer)
+ {
+ }
+
+ //***************************************************
+ const_iterator(const typename ideque::iterator& other)
+ : index(other.index),
+ p_deque(other.p_deque),
+ p_buffer(other.p_buffer)
+ {
+ }
+
+ //***************************************************
+ const_iterator& operator ++()
+ {
+ index = (index == p_deque->BUFFER_SIZE - 1) ? 0 : index + 1;
+
+ return *this;
+ }
+
+ //***************************************************
+ const_iterator operator ++(int)
+ {
+ const_iterator previous(*this);
+ index = (static_cast<size_t>(index) == p_deque->BUFFER_SIZE - 1) ? 0 : index + 1;
+
+ return previous;
+ }
+
+ //***************************************************
+ const_iterator& operator +=(difference_type offset)
+ {
+ if (offset > 0)
+ {
+ index += offset;
+ index = (static_cast<size_t>(index) > p_deque->BUFFER_SIZE - 1) ? index - p_deque->BUFFER_SIZE : index;
+ }
+ else if (offset < 0)
+ {
+ operator -= (-offset);
+ }
+
+ return *this;
+ }
+
+ //***************************************************
+ const_iterator& operator -=(difference_type offset)
+ {
+ if (offset > 0)
+ {
+ index -= offset;
+ index = (index < 0) ? index + p_deque->BUFFER_SIZE : index;
+ }
+ else if (offset < 0)
+ {
+ operator += (-offset);
+ }
+
+ return *this;
+ }
+
+ //***************************************************
+ const_iterator& operator --()
+ {
+ index = (index == 0) ? p_deque->BUFFER_SIZE - 1 : index - 1;
+
+ return *this;
+ }
+
+ //***************************************************
+ const_iterator operator --(int)
+ {
+ const_iterator previous(*this);
+ index = (index == 0) ? p_deque->BUFFER_SIZE - 1 : index - 1;
+
+ return previous;
+ }
+
+ //***************************************************
+ const_reference operator *() const
+ {
+ return p_buffer[index];
+ }
+
+ //***************************************************
+ const_pointer operator ->() const
+ {
+ return &p_buffer[index];
+ }
+
+ //***************************************************
+ bool operator <(const const_iterator& other) const
+ {
+ return ideque::distance(*this, other) > 0;
+ }
+
+ //***************************************************
+ friend const_iterator operator +(const const_iterator& lhs, difference_type offset)
+ {
+ const_iterator result(lhs);
+ result += offset;
+ return result;
+ }
+
+ //***************************************************
+ friend const_iterator operator -(const const_iterator& lhs, difference_type offset)
+ {
+ const_iterator result(lhs);
+ result -= offset;
+ return result;
+ }
+
+ //***************************************************
+ friend bool operator == (const const_iterator& lhs, const const_iterator& rhs)
+ {
+ return lhs.index == rhs.index;
+ }
+
+ //***************************************************
+ friend bool operator != (const const_iterator& lhs, const const_iterator& rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+ //***************************************************
+ difference_type get_index() const
+ {
+ return index;
+ }
+
+ //***************************************************
+ ideque& get_deque() const
+ {
+ return *p_deque;
+ }
+
+ //***************************************************
+ pointer get_buffer() const
+ {
+ return p_buffer;
+ }
+
+ //***************************************************
+ void swap(const_iterator& other)
+ {
+ std::swap(index, other.index);
+ }
+
+ private:
+
+ //***************************************************
+ difference_type distance(difference_type firstIndex, difference_type index)
+ {
+ if (index < firstIndex)
+ {
+ return p_deque->BUFFER_SIZE + index - firstIndex;
+ }
+ else
+ {
+ return index - firstIndex;
+ }
+ }
+
+ //***************************************************
+ const_iterator(difference_type index, ideque& the_deque, pointer p_buffer)
+ : index(index),
+ p_deque(&the_deque),
+ p_buffer(p_buffer)
+ {
+ }
+
+ difference_type index;
+ ideque* p_deque;
+ pointer p_buffer;
+ };
+
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+
+ //*************************************************************************
+ /// Assigns a range to the deque.
+ //*************************************************************************
+ template<typename TIterator>
+ typename etl::enable_if<is_iterator<TIterator>::value, void>::type
+ assign(TIterator range_begin, TIterator range_end)
+ {
+ initialise();
+
+ while (range_begin != range_end)
+ {
+ push_back(*range_begin++);
+ }
+ }
+
+ //*************************************************************************
+ /// Assigns 'n' copies of a value to the deque.
+ /// If asserts or exceptions are enabled, throws an etl::deque_full is 'n' is too large.
+ ///\param n The number of copies to assign.
+ ///\param value The value to add.<
+ //*************************************************************************
+ void assign(size_type n, const value_type& value)
+ {
+ ETL_ASSERT(n <= MAX_SIZE, ETL_ERROR(deque_full));
+
+ initialise();
+
+ _begin.index = 0;
+ _end.index = 0;
+
+ while (n > 0)
+ {
+ create_element_back(value);
+ --n;
+ }
+ }
+
+ //*************************************************************************
+ /// Gets a reference to the item at the index.
+ /// If asserts or exceptions are enabled, throws an etl::deque_out_of_bounds if the index is out of range.
+ ///\return A reference to the item at the index.
+ //*************************************************************************
+ reference at(size_t index)
+ {
+ ETL_ASSERT(index < current_size, ETL_ERROR(deque_out_of_bounds));
+
+ iterator result(_begin);
+ result += index;
+
+ return *result;
+ }
+
+ //*************************************************************************
+ /// Gets a const reference to the item at the index.
+ /// If asserts or exceptions are enabled, throws an etl::deque_out_of_bounds if the index is out of range.
+ ///\return A const reference to the item at the index.
+ //*************************************************************************
+ const_reference at(size_t index) const
+ {
+ ETL_ASSERT(index < current_size, ETL_ERROR(deque_out_of_bounds));
+
+ iterator result(_begin);
+ result += index;
+
+ return *result;
+ }
+
+ //*************************************************************************
+ /// Gets a reference to the item at the index.
+ ///\return A reference to the item at the index.
+ //*************************************************************************
+ reference operator [](size_t index)
+ {
+ iterator result(_begin);
+ result += index;
+
+ return *result;
+ }
+
+ //*************************************************************************
+ /// Gets a const reference to the item at the index.
+ ///\return A const reference to the item at the index.
+ //*************************************************************************
+ const_reference operator [](size_t index) const
+ {
+ iterator result(_begin);
+ result += index;
+
+ return *result;
+ }
+
+ //*************************************************************************
+ /// Gets a reference to the item at the front of the deque.
+ ///\return A reference to the item at the front of the deque.
+ //*************************************************************************
+ reference front()
+ {
+ return *_begin;
+ }
+
+ //*************************************************************************
+ /// Gets a const reference to the item at the front of the deque.
+ ///\return A const reference to the item at the front of the deque.
+ //*************************************************************************
+ const_reference front() const
+ {
+ return *_begin;
+ }
+
+ //*************************************************************************
+ /// Gets a reference to the item at the back of the deque.
+ ///\return A reference to the item at the back of the deque.
+ //*************************************************************************
+ reference back()
+ {
+ return *(_end - 1);
+ }
+
+ //*************************************************************************
+ /// Gets a const reference to the item at the back of the deque.
+ ///\return A const reference to the item at the back of the deque.
+ //*************************************************************************
+ const_reference back() const
+ {
+ return *(_end - 1);
+ }
+
+ //*************************************************************************
+ /// Gets an iterator to the beginning of the deque.
+ //*************************************************************************
+ iterator begin()
+ {
+ return _begin;
+ }
+
+ //*************************************************************************
+ /// Gets a const iterator to the beginning of the deque.
+ //*************************************************************************
+ const_iterator begin() const
+ {
+ return _begin;
+ }
+
+ //*************************************************************************
+ /// Gets a const iterator to the beginning of the deque.
+ //*************************************************************************
+ const_iterator cbegin() const
+ {
+ return _begin;
+ }
+
+ //*************************************************************************
+ /// Gets an iterator to the end of the deque.
+ //*************************************************************************
+ iterator end()
+ {
+ return iterator(_end);
+ }
+
+ //*************************************************************************
+ /// Gets a const iterator to the end of the deque.
+ //*************************************************************************
+ const_iterator end() const
+ {
+ return iterator(_end);
+ }
+
+ //*************************************************************************
+ /// Gets a const iterator to the end of the deque.
+ //*************************************************************************
+ const_iterator cend() const
+ {
+ return const_iterator(_end);
+ }
+
+ //*************************************************************************
+ /// Gets a reverse iterator to the end of the deque.
+ //*************************************************************************
+ reverse_iterator rbegin()
+ {
+ return reverse_iterator(end());
+ }
+
+ //*************************************************************************
+ /// Gets a const reverse iterator to the end of the deque.
+ //*************************************************************************
+ const_reverse_iterator rbegin() const
+ {
+ return const_reverse_iterator(end());
+ }
+
+ //*************************************************************************
+ /// Gets a const reverse iterator to the end of the deque.
+ //*************************************************************************
+ const_reverse_iterator crbegin() const
+ {
+ return const_reverse_iterator(cend());
+ }
+
+ //*************************************************************************
+ /// Gets a reverse iterator to the beginning of the deque.
+ //*************************************************************************
+ reverse_iterator rend()
+ {
+ return reverse_iterator(begin());
+ }
+
+ //*************************************************************************
+ /// Gets a const reverse iterator to the beginning of the deque.
+ //*************************************************************************
+ const_reverse_iterator rend() const
+ {
+ return const_reverse_iterator(begin());
+ }
+
+ //*************************************************************************
+ /// Gets a const reverse iterator to the beginning of the deque.
+ //*************************************************************************
+ const_reverse_iterator crend() const
+ {
+ return const_reverse_iterator(cbegin());
+ }
+
+ //*************************************************************************
+ /// Clears the deque.
+ //*************************************************************************
+ void clear()
+ {
+ initialise();
+ }
+
+ //*************************************************************************
+ /// Inserts data into the deque.
+ /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is full.
+ ///\param insert_position>The insert position.
+ ///\param value>The value to insert.
+ //*************************************************************************
+ iterator insert(const_iterator insert_position, const value_type& value)
+ {
+ iterator position(insert_position.index, *this, p_buffer);
+
+ ETL_ASSERT(!full(), ETL_ERROR(deque_full));
+
+ if (insert_position == begin())
+ {
+ create_element_front(value);
+ position = _begin;
+ }
+ else if (insert_position == end())
+ {
+ create_element_back(value);
+ position = _end - 1;
+ }
+ else
+ {
+ // Are we closer to the front?
+ if (std::distance(_begin, position) < std::distance(position, _end - 1))
+ {
+ // Construct the _begin.
+ create_element_front(*_begin);
+
+ // Move the values.
+ std::copy(_begin + 1, position, _begin);
+
+ // Write the new value.
+ *--position = value;
+ }
+ else
+ {
+ // Construct the _end.
+ create_element_back(*(_end - 1));
+
+ // Move the values.
+ std::copy_backward(position, _end - 2, _end - 1);
+
+ // Write the new value.
+ *position = value;
+ }
+ }
+
+ return position;
+ }
+
+ //*************************************************************************
+ /// Inserts 'n' copies of a value into the deque.
+ /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is full.
+ ///\param insert_position The insert position.
+ ///\param n The number of values to insert.
+ ///\param value The value to insert.
+ //*************************************************************************
+ iterator insert(const_iterator insert_position, size_type n, const value_type& value)
+ {
+ iterator position;
+
+ ETL_ASSERT((current_size + n) <= MAX_SIZE, ETL_ERROR(deque_full));
+
+ if (insert_position == begin())
+ {
+ for (size_t i = 0; i < n; ++i)
+ {
+ create_element_front(value);
+ }
+
+ position = _begin;
+ }
+ else if (insert_position == end())
+ {
+ for (size_t i = 0; i < n; ++i)
+ {
+ create_element_back(value);
+ }
+
+ position = _end - n;
+ }
+ else
+ {
+ // Non-const insert iterator.
+ position = iterator(insert_position.index, *this, p_buffer);
+
+ // Are we closer to the front?
+ if (distance(_begin, insert_position) <= difference_type(current_size / 2))
+ {
+ size_t n_insert = n;
+ size_t n_move = std::distance(begin(), position);
+ size_t n_create_copy = std::min(n_insert, n_move);
+ size_t n_create_new = (n_insert > n_create_copy) ? n_insert - n_create_copy : 0;
+ size_t n_copy_new = (n_insert > n_create_new) ? n_insert - n_create_new : 0;
+ size_t n_copy_old = n_move - n_create_copy;
+
+ // Remember the original start.
+ iterator from = _begin + n_create_copy - 1;
+ iterator to;
+
+ // Create new.
+ for (size_t i = 0; i < n_create_new; ++i)
+ {
+ create_element_front(value);
+ }
+
+ // Create copy.
+ for (size_t i = 0; i < n_create_copy; ++i)
+ {
+ create_element_front(*from--);
+ }
+
+ // Copy old.
+ from = position - n_copy_old;
+ to = _begin + n_create_copy;
+ etl::copy_n(from, n_copy_old, to);
+
+ // Copy new.
+ to = position - n_create_copy;
+ std::fill_n(to, n_copy_new, value);
+
+ position = _begin + n_move;
+ }
+ else
+ {
+ size_t n_insert = n;
+ size_t n_move = std::distance(position, end());
+ size_t n_create_copy = std::min(n_insert, n_move);
+ size_t n_create_new = (n_insert > n_create_copy) ? n_insert - n_create_copy : 0;
+ size_t n_copy_new = (n_insert > n_create_new) ? n_insert - n_create_new : 0;
+ size_t n_copy_old = n_move - n_create_copy;
+
+ // Create new.
+ for (size_t i = 0; i < n_create_new; ++i)
+ {
+ create_element_back(value);
+ }
+
+ // Create copy.
+ const_iterator from = position + n_copy_old;
+
+ for (size_t i = 0; i < n_create_copy; ++i)
+ {
+ create_element_back(*from++);
+ }
+
+ // Copy old.
+ std::copy_backward(position, position + n_copy_old, position + n_insert + n_copy_old);
+
+ // Copy new.
+ std::fill_n(position, n_copy_new, value);
+ }
+ }
+
+ return position;
+ }
+
+ //*************************************************************************
+ /// Inserts a range into the deque.
+ /// If asserts or exceptions are enabled, throws an etl::deque_empty if the deque is full.
+ ///\param insert_position>The insert position.
+ ///\param range_begin The beginning of the range to insert.
+ ///\param range_end The end of the range to insert.
+ //*************************************************************************
+ template<typename TIterator>
+ typename enable_if<is_iterator<TIterator>::value, iterator>::type
+ insert(const_iterator insert_position, TIterator range_begin, TIterator range_end)
+ {
+ iterator position;
+
+ difference_type n = std::distance(range_begin, range_end);
+
+ ETL_ASSERT((current_size + n) <= MAX_SIZE, ETL_ERROR(deque_full));
+
+ if (insert_position == begin())
+ {
+ create_element_front(n, range_begin);
+
+ position = _begin;
+ }
+ else if (insert_position == end())
+ {
+ for (difference_type i = 0; i < n; ++i)
+ {
+ create_element_back(*range_begin++);
+ }
+
+ position = _end - n;
+ }
+ else
+ {
+ // Non-const insert iterator.
+ position = iterator(insert_position.index, *this, p_buffer);
+
+ // Are we closer to the front?
+ if (distance(_begin, insert_position) < difference_type(current_size / 2))
+ {
+ size_t n_insert = n;
+ size_t n_move = std::distance(begin(), position);
+ size_t n_create_copy = std::min(n_insert, n_move);
+ size_t n_create_new = (n_insert > n_create_copy) ? n_insert - n_create_copy : 0;
+ size_t n_copy_new = (n_insert > n_create_new) ? n_insert - n_create_new : 0;
+ size_t n_copy_old = n_move - n_create_copy;
+
+ // Remember the original start.
+ iterator from;
+ iterator to;
+
+ // Create new.
+ create_element_front(n_create_new, range_begin);
+
+ // Create copy.
+ create_element_front(n_create_copy, _begin + n_create_new);
+
+ // Copy old.
+ from = position - n_copy_old;
+ to = _begin + n_create_copy;
+ etl::copy_n(from, n_copy_old, to);
+
+ // Copy new.
+ to = position - n_create_copy;
+ range_begin += n_create_new;
+ etl::copy_n(range_begin, n_copy_new, to);
+
+ position = _begin + n_move;
+ }
+ else
+ {
+ size_t n_insert = n;
+ size_t n_move = std::distance(position, end());
+ size_t n_create_copy = std::min(n_insert, n_move);
+ size_t n_create_new = (n_insert > n_create_copy) ? n_insert - n_create_copy : 0;
+ size_t n_copy_new = (n_insert > n_create_new) ? n_insert - n_create_new : 0;
+ size_t n_copy_old = n_move - n_create_copy;
+
+ // Create new.
+ TIterator item = range_begin + (n - n_create_new);
+ for (size_t i = 0; i < n_create_new; ++i)
+ {
+ create_element_back(*item++);
+ }
+
+ // Create copy.
+ const_iterator from = position + n_copy_old;
+
+ for (size_t i = 0; i < n_create_copy; ++i)
+ {
+ create_element_back(*from++);
+ }
+
+ // Copy old.
+ std::copy_backward(position, position + n_copy_old, position + n_insert + n_copy_old);
+
+ // Copy new.
+ item = range_begin;
+ etl::copy_n(item, n_copy_new, position);
+ }
+ }
+
+ return position;
+ }
+
+ //*************************************************************************
+ /// Erase an item.
+ /// If asserts or exceptions are enabled, throws an etl::deque_out_of_bounds if the position is out of range.
+ ///\param erase_position The position to erase.
+ //*************************************************************************
+ iterator erase(const_iterator erase_position)
+ {
+ iterator position(erase_position.index, *this, p_buffer);
+
+ ETL_ASSERT(distance(position) <= difference_type(current_size), ETL_ERROR(deque_out_of_bounds));
+
+ if (position == _begin)
+ {
+ destroy_element_front();
+ position = begin();
+ }
+ else if (position == _end - 1)
+ {
+ destroy_element_back();
+ position = end();
+ }
+ else
+ {
+ // Are we closer to the front?
+ if (distance(_begin, position) < difference_type(current_size / 2))
+ {
+ std::copy_backward(_begin, position, position + 1);
+ destroy_element_front();
+ ++position;
+ }
+ else
+ {
+ std::copy(position + 1, _end, position);
+ destroy_element_back();
+ }
+ }
+
+ return position;
+ }
+
+ //*************************************************************************
+ /// erase a range.
+ /// If asserts or exceptions are enabled, throws an etl::deque_out_of_bounds if the iterators are out of range.
+ ///\param range_begin The beginning of the range to erase.
+ ///\param range_end The end of the range to erase.
+ //*************************************************************************
+ iterator erase(const_iterator range_begin, const_iterator range_end)
+ {
+ iterator position(range_begin.index, *this, p_buffer);
+
+ ETL_ASSERT((distance(range_begin) <= difference_type(current_size)) && (distance(range_end) <= difference_type(current_size)), ETL_ERROR(deque_out_of_bounds));
+
+ // How many to erase?
+ size_t length = std::distance(range_begin, range_end);
+
+ // At the beginning?
+ if (position == _begin)
+ {
+ for (size_t i = 0; i < length; ++i)
+ {
+ destroy_element_front();
+ }
+
+ position = begin();
+ }
+ // At the end?
+ else if (position == _end - length)
+ {
+ for (size_t i = 0; i < length; ++i)
+ {
+ destroy_element_back();
+ }
+
+ position = end();
+ }
+ else
+ {
+ // Copy the smallest number of items.
+ // Are we closer to the front?
+ if (distance(_begin, position) < difference_type(current_size / 2))
+ {
+ // Move the items.
+ std::copy_backward(_begin, position, position + length);
+
+ for (size_t i = 0; i < length; ++i)
+ {
+ destroy_element_front();
+ }
+
+ position += length;
+ }
+ else
+ // Must be closer to the back.
+ {
+ // Move the items.
+ std::copy(position + length, _end, position);
+
+ for (size_t i = 0; i < length; ++i)
+ {
+ destroy_element_back();
+ }
+ }
+ }
+
+ return position;
+ }
+
+ //*************************************************************************
+ /// Adds an item to the back of the deque.
+ /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is already full.
+ ///\param item The item to push to the deque.
+ //*************************************************************************
+ void push_back(parameter_t item)
+ {
+#if defined(ETL_CHECK_PUSH_POP)
+ ETL_ASSERT(!full(), ETL_ERROR(deque_full));
+#endif
+ create_element_back(item);
+ }
+
+ //*************************************************************************
+ /// Adds one to the front of the deque and returns a reference to the new element.
+ /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is already full.
+ ///\return A reference to the item to assign to.
+ //*************************************************************************
+ reference push_back()
+ {
+ reference r = *_end;
+#if defined(ETL_CHECK_PUSH_POP)
+ ETL_ASSERT(!full(), ETL_ERROR(deque_full));
+#endif
+ create_element_back();
+
+ return r;
+ }
+
+ //*************************************************************************
+ /// Removes the oldest item from the deque.
+ //*************************************************************************
+ void pop_back()
+ {
+#if defined(ETL_CHECK_PUSH_POP)
+ ETL_ASSERT(!empty(), ETL_ERROR(deque_empty));
+#endif
+ destroy_element_back();
+ }
+
+ //*************************************************************************
+ /// Adds an item to the front of the deque.
+ /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is already full.
+ ///\param item The item to push to the deque.
+ //*************************************************************************
+ void push_front(parameter_t item)
+ {
+#if defined(ETL_CHECK_PUSH_POP)
+ ETL_ASSERT(!full(), ETL_ERROR(deque_full));
+#endif
+ create_element_front(item);
+ }
+
+ //*************************************************************************
+ /// Adds one to the front of the deque and returns a reference to the new element.
+ /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is already full.
+ ///\return A reference to the item to assign to.
+ //*************************************************************************
+ reference push_front()
+ {
+#if defined(ETL_CHECK_PUSH_POP)
+ ETL_ASSERT(!full(), ETL_ERROR(deque_full));
+#endif
+ create_element_front();
+
+ return *_begin;
+ }
+
+ //*************************************************************************
+ /// Removes the oldest item from the deque.
+ //*************************************************************************
+ void pop_front()
+ {
+#if defined(ETL_CHECK_PUSH_POP)
+ ETL_ASSERT(!empty(), ETL_ERROR(deque_empty));
+#endif
+ destroy_element_front();
+ }
+
+ //*************************************************************************
+ /// Resizes the deque.
+ /// If asserts or exceptions are enabled, throws an etl::deque_full is 'new_size' is too large.
+ ///\param new_size The new size of the deque.
+ ///\param value The value to assign if the new size is larger. Default = Default constructed value.
+ //*************************************************************************
+ void resize(size_t new_size, const value_type& value = value_type())
+ {
+ ETL_ASSERT(new_size <= MAX_SIZE, ETL_ERROR(deque_out_of_bounds));
+
+ // Make it smaller?
+ if (new_size < current_size)
+ {
+ while (current_size > new_size)
+ {
+ destroy_element_back();
+ }
+ }
+ // Make it larger?
+ else if (new_size > current_size)
+ {
+ size_t count = new_size - current_size;
+
+ for (size_t i = 0; i < count; ++i)
+ {
+ create_element_back(value);
+ }
+ }
+ }
+
+ //*************************************************************************
+ /// - operator for iterator
+ //*************************************************************************
+ friend difference_type operator -(const iterator& lhs, const iterator& rhs)
+ {
+ return distance(rhs, lhs);
+ }
+
+ //*************************************************************************
+ /// - operator for const_iterator
+ //*************************************************************************
+ friend difference_type operator -(const const_iterator& lhs, const const_iterator& rhs)
+ {
+ return distance(rhs, lhs);
+ }
+
+ //*************************************************************************
+ /// - operator for reverse_iterator
+ //*************************************************************************
+ friend difference_type operator -(const reverse_iterator& lhs, const reverse_iterator& rhs)
+ {
+ return distance(lhs.base(), rhs.base());
+ }
+
+ //*************************************************************************
+ /// - operator for const_reverse_iterator
+ //*************************************************************************
+ friend difference_type operator -(const const_reverse_iterator& lhs, const const_reverse_iterator& rhs)
+ {
+ return distance(lhs.base(), rhs.base());
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ ideque& operator =(const ideque& rhs)
+ {
+ if (&rhs != this)
+ {
+ assign(rhs.begin(), rhs.end());
+ }
+
+ return *this;
+ }
+
+ protected:
+
+ //*************************************************************************
+ /// Constructor.
+ //*************************************************************************
+ ideque(pointer p_buffer, size_t max_size, size_t buffer_size)
+ : deque_base(max_size, buffer_size),
+ p_buffer(p_buffer)
+ {
+ }
+
+ //*********************************************************************
+ /// Initialise the deque.
+ //*********************************************************************
+ void initialise()
+ {
+ while (current_size > 0)
+ {
+ destroy_element_back();
+ }
+
+ _begin = iterator(0, *this, p_buffer);
+ _end = iterator(0, *this, p_buffer);
+ }
+
+ iterator _begin; ///Iterator to the _begin item in the deque.
+ iterator _end; ///Iterator to the _end item in the deque.
+ pointer p_buffer; ///The buffer for the deque.
+
+ private:
+
+ //*********************************************************************
+ /// Create a new element with a default value at the front.
+ //*********************************************************************
+ void create_element_front()
+ {
+ if (!empty())
+ {
+ --_begin;
+ }
+
+ new(&(*_begin)) T();
+ ++current_size;
+ }
+
+ //*********************************************************************
+ /// Create a new elements from a range at the front.
+ //*********************************************************************
+ template <typename TIterator>
+ void create_element_front(size_t n, TIterator from)
+ {
+ if (n == 0)
+ {
+ return;
+ }
+
+ if (!empty())
+ {
+ --_begin;
+ --n;
+ }
+
+ if (n > 0)
+ {
+ _begin -= n;
+ }
+
+ iterator item = _begin;
+
+ do
+ {
+ new(&(*item++)) T(*from);
+ ++from;
+ ++current_size;
+ } while (n-- != 0);
+ }
+
+ //*********************************************************************
+ /// Create a new element with a default value at the back.
+ //*********************************************************************
+ void create_element_back()
+ {
+ new(&(*_end)) T();
+ ++_end;
+ ++current_size;
+ }
+
+ //*********************************************************************
+ /// Create a new element with a default value at the front.
+ //*********************************************************************
+ void create_element_front(parameter_t value)
+ {
+ --_begin;
+ new(&(*_begin)) T(value);
+ ++current_size;
+ }
+
+ //*********************************************************************
+ /// Create a new element with a value at the back
+ //*********************************************************************
+ void create_element_back(parameter_t value)
+ {
+ new(&(*_end)) T(value);
+ ++_end;
+ ++current_size;
+ }
+
+ //*********************************************************************
+ /// Destroy an element at the front.
+ //*********************************************************************
+ void destroy_element_front()
+ {
+ (*_begin).~T();
+ --current_size;
+ ++_begin;
+ }
+
+ //*********************************************************************
+ /// Destroy an element at the back.
+ //*********************************************************************
+ void destroy_element_back()
+ {
+ --_end;
+ (*_end).~T();
+ --current_size;
+ }
+
+ //*************************************************************************
+ /// Measures the distance between two iterators.
+ //*************************************************************************
+ template <typename TIterator1, typename TIterator2>
+ static difference_type distance(const TIterator1& range_begin, const TIterator2& range_end)
+ {
+ difference_type distance1 = distance(range_begin);
+ difference_type distance2 = distance(range_end);
+
+ return distance2 - distance1;
+ }
+
+ //*************************************************************************
+ /// Measures the distance from the _begin iterator to the specified iterator.
+ //*************************************************************************
+ template <typename TIterator>
+ static difference_type distance(const TIterator& other)
+ {
+ const difference_type index = other.get_index();
+ const difference_type reference_index = other.get_deque()._begin.index;
+ const size_t buffer_size = other.get_deque().BUFFER_SIZE;
+
+ if (index < reference_index)
+ {
+ return buffer_size + index - reference_index;
+ }
+ else
+ {
+ return index - reference_index;
+ }
+ }
+
+ // Disable copy construction.
+ ideque(const ideque&);
+ };
+}
+
+//***************************************************************************
+/// Equal operator.
+///\param lhs Reference to the _begin deque.
+///\param rhs Reference to the second deque.
+///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
+///\ingroup deque
+//***************************************************************************
+template <typename T>
+bool operator ==(const etl::ideque<T>& lhs, const etl::ideque<T>& rhs)
+{
+ return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin());
+}
+
+//***************************************************************************
+/// Not equal operator.
+///\param lhs Reference to the _begin deque.
+///\param rhs Reference to the second deque.
+///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
+///\ingroup deque
+//***************************************************************************
+template <typename T>
+bool operator !=(const etl::ideque<T>& lhs, const etl::ideque<T>& rhs)
+{
+ return !(lhs == rhs);
+}
+
+//***************************************************************************
+/// Less than operator.
+///\param lhs Reference to the _begin deque.
+///\param rhs Reference to the second deque.
+///\return <b>true</b> if the _begin deque is lexicographically less than the second, otherwise <b>false</b>
+///\ingroup deque
+//***************************************************************************
+template <typename T>
+bool operator <(const etl::ideque<T>& lhs, const etl::ideque<T>& rhs)
+{
+ return std::lexicographical_compare(lhs.begin(),
+ lhs.end(),
+ rhs.begin(),
+ rhs.end());
+}
+
+//***************************************************************************
+/// Less than or equal operator.
+///\param lhs Reference to the _begin deque.
+///\param rhs Reference to the second deque.
+///\return <b>true</b> if the _begin deque is lexicographically less than or equal to the second, otherwise <b>false</b>
+///\ingroup deque
+//***************************************************************************
+template <typename T>
+bool operator <=(const etl::ideque<T>& lhs, const etl::ideque<T>& rhs)
+{
+ return !(lhs > rhs);
+}
+
+//***************************************************************************
+/// Greater than operator.
+///\param lhs Reference to the _begin deque.
+///\param rhs Reference to the second deque.
+///\return <b>true</b> if the _begin deque is lexicographically greater than the second, otherwise <b>false</b>
+///\ingroup deque
+//***************************************************************************
+template <typename T>
+bool operator >(const etl::ideque<T>& lhs, const etl::ideque<T>& rhs)
+{
+ return (rhs < lhs);
+}
+
+//***************************************************************************
+/// Greater than or equal operator.
+///\param "lhs Reference to the _begin deque.
+///\param "rhs Reference to the second deque.
+///\return <b>true</b> if the _begin deque is lexicographically greater than or equal to the second, otherwise <b>false</b>
+///\ingroup deque
+//***************************************************************************
+template <typename T>
+bool operator >=(const etl::ideque<T>& lhs, const etl::ideque<T>& rhs)
+{
+ return !(lhs < rhs);
+}
+
+#undef __ETL_IN_IDEQUE_H__
+
+#endif
diff --git a/lib/etl/iflat_map.h b/lib/etl/iflat_map.h
new file mode 100644
index 0000000..399897f
--- /dev/null
+++ b/lib/etl/iflat_map.h
@@ -0,0 +1,581 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2015 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_IFLAT_MAP__
+#define __ETL_IFLAT_MAP__
+#define __ETL_IN_IFLAT_MAP_H__
+
+#include <iterator>
+#include <algorithm>
+#include <functional>
+#include <utility>
+#include <stddef.h>
+
+#include "private/flat_map_base.h"
+#include "type_traits.h"
+#include "parameter_type.h"
+#include "ivector.h"
+#include "error_handler.h"
+
+namespace etl
+{
+ //***************************************************************************
+ /// The base class for specifically sized flat_maps.
+ /// Can be used as a reference type for all flat_maps containing a specific type.
+ ///\ingroup flat_map
+ //***************************************************************************
+ template <typename TKey, typename TMapped, typename TKeyCompare = std::less<TKey> >
+ class iflat_map : public flat_map_base
+ {
+ public:
+
+ typedef std::pair<TKey, TMapped> value_type;
+
+ private:
+
+ typedef etl::ivector<value_type> buffer_t;
+
+ public:
+
+ typedef TKey key_type;
+ typedef TMapped mapped_type;
+ typedef TKeyCompare key_compare;
+ typedef value_type& reference;
+ typedef const value_type& const_reference;
+ typedef value_type* pointer;
+ typedef const value_type* const_pointer;
+ typedef typename buffer_t::iterator iterator;
+ typedef typename buffer_t::const_iterator const_iterator;
+ typedef typename buffer_t::reverse_iterator reverse_iterator;
+ typedef typename buffer_t::const_reverse_iterator const_reverse_iterator;
+ typedef size_t size_type;
+ typedef typename std::iterator_traits<iterator>::difference_type difference_type;
+
+ protected:
+
+ typedef typename parameter_type<TKey>::type key_value_parameter_t;
+
+ private:
+
+ //*********************************************************************
+ /// How to compare elements and keys.
+ //*********************************************************************
+ class compare
+ {
+ public:
+
+ bool operator ()(const value_type& element, key_type key) const
+ {
+ return key_compare()(element.first, key);
+ }
+
+ bool operator ()(key_type key, const value_type& element) const
+ {
+ return key_compare()(key, element.first);
+ }
+ };
+
+ public:
+
+ //*********************************************************************
+ /// Returns an iterator to the beginning of the flat_map.
+ ///\return An iterator to the beginning of the flat_map.
+ //*********************************************************************
+ iterator begin()
+ {
+ return buffer.begin();
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the beginning of the flat_map.
+ ///\return A const iterator to the beginning of the flat_map.
+ //*********************************************************************
+ const_iterator begin() const
+ {
+ return buffer.begin();
+ }
+
+ //*********************************************************************
+ /// Returns an iterator to the end of the flat_map.
+ ///\return An iterator to the end of the flat_map.
+ //*********************************************************************
+ iterator end()
+ {
+ return buffer.end();
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the end of the flat_map.
+ ///\return A const iterator to the end of the flat_map.
+ //*********************************************************************
+ const_iterator end() const
+ {
+ return buffer.end();
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the beginning of the flat_map.
+ ///\return A const iterator to the beginning of the flat_map.
+ //*********************************************************************
+ const_iterator cbegin() const
+ {
+ return buffer.cbegin();
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the end of the flat_map.
+ ///\return A const iterator to the end of the flat_map.
+ //*********************************************************************
+ const_iterator cend() const
+ {
+ return buffer.cend();
+ }
+
+ //*********************************************************************
+ /// Returns an reverse iterator to the reverse beginning of the flat_map.
+ ///\return Iterator to the reverse beginning of the flat_map.
+ //*********************************************************************
+ reverse_iterator rbegin()
+ {
+ return buffer.rbegin();
+ }
+
+ //*********************************************************************
+ /// Returns a const reverse iterator to the reverse beginning of the flat_map.
+ ///\return Const iterator to the reverse beginning of the flat_map.
+ //*********************************************************************
+ const_reverse_iterator rbegin() const
+ {
+ return buffer.rbegin();
+ }
+
+ //*********************************************************************
+ /// Returns a reverse iterator to the end + 1 of the flat_map.
+ ///\return Reverse iterator to the end + 1 of the flat_map.
+ //*********************************************************************
+ reverse_iterator rend()
+ {
+ return buffer.rend();
+ }
+
+ //*********************************************************************
+ /// Returns a const reverse iterator to the end + 1 of the flat_map.
+ ///\return Const reverse iterator to the end + 1 of the flat_map.
+ //*********************************************************************
+ const_reverse_iterator rend() const
+ {
+ return buffer.rend();
+ }
+
+ //*********************************************************************
+ /// Returns a const reverse iterator to the reverse beginning of the flat_map.
+ ///\return Const reverse iterator to the reverse beginning of the flat_map.
+ //*********************************************************************
+ const_reverse_iterator crbegin() const
+ {
+ return buffer.crbegin();
+ }
+
+ //*********************************************************************
+ /// Returns a const reverse iterator to the end + 1 of the flat_map.
+ ///\return Const reverse iterator to the end + 1 of the flat_map.
+ //*********************************************************************
+ const_reverse_iterator crend() const
+ {
+ return buffer.crend();
+ }
+
+ //*********************************************************************
+ /// Returns a reference to the value at index 'key'
+ ///\param i The index.
+ ///\return A reference to the value at index 'key'
+ //*********************************************************************
+ mapped_type& operator [](key_value_parameter_t key)
+ {
+ iterator i_element = lower_bound(key);
+
+ if (i_element == end())
+ {
+ // Doesn't exist, so create a new one.
+ value_type value(key, mapped_type());
+ i_element = insert(value).first;
+ }
+
+ return i_element->second;
+ }
+
+ //*********************************************************************
+ /// Returns a reference to the value at index 'key'
+ /// If asserts or exceptions are enabled, emits an etl::flat_map_out_of_bounds if the key is not in the range.
+ ///\param i The index.
+ ///\return A reference to the value at index 'key'
+ //*********************************************************************
+ mapped_type& at(key_value_parameter_t key)
+ {
+ iterator i_element = lower_bound(key);
+
+ ETL_ASSERT(i_element != end(), ETL_ERROR(flat_map_out_of_bounds));
+
+ return i_element->second;
+ }
+
+ //*********************************************************************
+ /// Returns a const reference to the value at index 'key'
+ /// If asserts or exceptions are enabled, emits an etl::flat_map_out_of_bounds if the key is not in the range.
+ ///\param i The index.
+ ///\return A const reference to the value at index 'key'
+ //*********************************************************************
+ const mapped_type& at(key_value_parameter_t key) const
+ {
+ typename buffer_t::const_iterator i_element = lower_bound(key);
+
+ ETL_ASSERT(i_element != end(), ETL_ERROR(flat_map_out_of_bounds));
+
+ return i_element->second;
+ }
+
+ //*********************************************************************
+ /// Assigns values to the flat_map.
+ /// If ETL_THROW_EXCEPTIONS & _DEBUG are defined, emits flat_map_full if the flat_map does not have enough free space.
+ /// If ETL_THROW_EXCEPTIONS & _DEBUG are defined, emits flat_map_iterator if the iterators are reversed.
+ ///\param first The iterator to the first element.
+ ///\param last The iterator to the last element + 1.
+ //*********************************************************************
+ template <typename TIterator>
+ void assign(TIterator first, TIterator last)
+ {
+#ifdef _DEBUG
+ difference_type count = std::distance(first, last);
+ ETL_ASSERT(count <= difference_type(capacity()), ETL_ERROR(flat_map_full));
+#endif
+
+ clear();
+
+ while (first != last)
+ {
+ insert(*first++);
+ }
+ }
+
+ //*********************************************************************
+ /// Inserts a value to the flat_map.
+ /// If asserts or exceptions are enabled, emits flat_map_full if the flat_map is already full.
+ ///\param value The value to insert.
+ //*********************************************************************
+ std::pair<iterator, bool> insert(const value_type& value)
+ {
+ std::pair<iterator, bool> result(end(), false);
+
+ iterator i_element = lower_bound(value.first);
+
+ if (i_element == end())
+ {
+ // At the end.
+ ETL_ASSERT(!buffer.full(), ETL_ERROR(flat_map_full));
+ buffer.push_back(value);
+ result.first = end() - 1;
+ result.second = true;
+ }
+ else
+ {
+ // Not at the end.
+ // Existing element?
+ if (value.first != i_element->first)
+ {
+ // A new one.
+ ETL_ASSERT(!buffer.full(), ETL_ERROR(flat_map_full));
+ buffer.insert(i_element, value);
+ result.first = i_element;
+ result.second = true;
+ }
+ }
+
+ return result;
+ }
+
+ //*********************************************************************
+ /// Inserts a value to the flat_map.
+ /// If asserts or exceptions are enabled, emits flat_map_full if the flat_map is already full.
+ ///\param position The position to insert at.
+ ///\param value The value to insert.
+ //*********************************************************************
+ iterator insert(iterator position, const value_type& value)
+ {
+ return insert(value).first;
+ }
+
+ //*********************************************************************
+ /// Inserts a range of values to the flat_map.
+ /// If asserts or exceptions are enabled, emits flat_map_full if the flat_map does not have enough free space.
+ ///\param position The position to insert at.
+ ///\param first The first element to add.
+ ///\param last The last + 1 element to add.
+ //*********************************************************************
+ template <class TIterator>
+ void insert(TIterator first, TIterator last)
+ {
+ while (first != last)
+ {
+ insert(*first++);
+ }
+ }
+
+ //*********************************************************************
+ /// Erases an element.
+ ///\param key The key to erase.
+ ///\return The number of elements erased. 0 or 1.
+ //*********************************************************************
+ size_t erase(key_value_parameter_t key)
+ {
+ iterator i_element = find(key);
+
+ if (i_element == end())
+ {
+ return 0;
+ }
+ else
+ {
+ buffer.erase(i_element);
+ return 1;
+ }
+ }
+
+ //*********************************************************************
+ /// Erases an element.
+ ///\param i_element Iterator to the element.
+ //*********************************************************************
+ void erase(iterator i_element)
+ {
+ buffer.erase(i_element);
+ }
+
+ //*********************************************************************
+ /// Erases a range of elements.
+ /// The range includes all the elements between first and last, including the
+ /// element pointed by first, but not the one pointed by last.
+ ///\param first Iterator to the first element.
+ ///\param last Iterator to the last element.
+ //*********************************************************************
+ void erase(iterator first, iterator last)
+ {
+ buffer.erase(first, last);
+ }
+
+ //*************************************************************************
+ /// Clears the flat_map.
+ //*************************************************************************
+ void clear()
+ {
+ buffer.clear();
+ }
+
+ //*********************************************************************
+ /// Finds an element.
+ ///\param key The key to search for.
+ ///\return An iterator pointing to the element or end() if not found.
+ //*********************************************************************
+ iterator find(key_value_parameter_t key)
+ {
+ iterator itr = lower_bound(key);
+
+ if (itr != end())
+ {
+ if (!key_compare()(itr->first, key) && !key_compare()(key, itr->first))
+ {
+ return itr;
+ }
+ else
+ {
+ return end();
+ }
+ }
+
+ return end();
+ }
+
+ //*********************************************************************
+ /// Finds an element.
+ ///\param key The key to search for.
+ ///\return An iterator pointing to the element or end() if not found.
+ //*********************************************************************
+ const_iterator find(key_value_parameter_t key) const
+ {
+ const_iterator itr = lower_bound(key);
+
+ if (itr != end())
+ {
+ if (!key_compare()(itr->first, key) && !key_compare()(key, itr->first))
+ {
+ return itr;
+ }
+ else
+ {
+ return end();
+ }
+ }
+
+ return end();
+ }
+
+ //*********************************************************************
+ /// Counts an element.
+ ///\param key The key to search for.
+ ///\return 1 if the key exists, otherwise 0.
+ //*********************************************************************
+ size_t count(key_value_parameter_t key) const
+ {
+ return (find(key) == end()) ? 0 : 1;
+ }
+
+ //*********************************************************************
+ /// Finds the lower bound of a key
+ ///\param key The key to search for.
+ ///\return An iterator.
+ //*********************************************************************
+ iterator lower_bound(key_value_parameter_t key)
+ {
+ return std::lower_bound(begin(), end(), key, compare());
+ }
+
+ //*********************************************************************
+ /// Finds the lower bound of a key
+ ///\param key The key to search for.
+ ///\return An iterator.
+ //*********************************************************************
+ const_iterator lower_bound(key_value_parameter_t key) const
+ {
+ return std::lower_bound(cbegin(), cend(), key, compare());
+ }
+
+ //*********************************************************************
+ /// Finds the upper bound of a key
+ ///\param key The key to search for.
+ ///\return An iterator.
+ //*********************************************************************
+ iterator upper_bound(key_value_parameter_t key)
+ {
+ return std::upper_bound(begin(), end(), key, compare());
+ }
+
+ //*********************************************************************
+ /// Finds the upper bound of a key
+ ///\param key The key to search for.
+ ///\return An iterator.
+ //*********************************************************************
+ const_iterator upper_bound(key_value_parameter_t key) const
+ {
+ return std::upper_bound(begin(), end(), key, compare());
+ }
+
+ //*********************************************************************
+ /// Finds the range of equal elements of a key
+ ///\param key The key to search for.
+ ///\return An iterator pair.
+ //*********************************************************************
+ std::pair<iterator, iterator> equal_range(key_value_parameter_t key)
+ {
+ iterator i_lower = std::lower_bound(begin(), end(), key, compare());
+
+ return std::make_pair(i_lower, std::upper_bound(i_lower, end(), key, compare()));
+ }
+
+ //*********************************************************************
+ /// Finds the range of equal elements of a key
+ ///\param key The key to search for.
+ ///\return An iterator pair.
+ //*********************************************************************
+ std::pair<const_iterator, const_iterator> equal_range(key_value_parameter_t key) const
+ {
+ const_iterator i_lower = std::lower_bound(cbegin(), cend(), key, compare());
+
+ return std::make_pair(i_lower, std::upper_bound(i_lower, cend(), key, compare()));
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ iflat_map& operator = (const iflat_map& rhs)
+ {
+ if (&rhs != this)
+ {
+ assign(rhs.cbegin(), rhs.cend());
+ }
+
+ return *this;
+ }
+
+ protected:
+
+ //*********************************************************************
+ /// Constructor.
+ //*********************************************************************
+ iflat_map(buffer_t& buffer)
+ : flat_map_base(buffer),
+ buffer(buffer)
+ {
+ }
+
+ private:
+
+ // Disable copy construction.
+ iflat_map(const iflat_map&);
+
+ buffer_t& buffer;
+ };
+
+ //***************************************************************************
+ /// Equal operator.
+ ///\param lhs Reference to the first flat_map.
+ ///\param rhs Reference to the second flat_map.
+ ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
+ ///\ingroup flat_map
+ //***************************************************************************
+ template <typename TKey, typename TMapped, typename TKeyCompare>
+ bool operator ==(const etl::iflat_map<TKey, TMapped, TKeyCompare>& lhs, const etl::iflat_map<TKey, TMapped, TKeyCompare>& rhs)
+ {
+ return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin());
+ }
+
+ //***************************************************************************
+ /// Not equal operator.
+ ///\param lhs Reference to the first flat_map.
+ ///\param rhs Reference to the second flat_map.
+ ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
+ ///\ingroup flat_map
+ //***************************************************************************
+ template <typename TKey, typename TMapped, typename TKeyCompare>
+ bool operator !=(const etl::iflat_map<TKey, TMapped, TKeyCompare>& lhs, const etl::iflat_map<TKey, TMapped, TKeyCompare>& rhs)
+ {
+ return !(lhs == rhs);
+ }
+}
+
+#undef __ETL_IN_IFLAT_MAP_H__
+#endif
diff --git a/lib/etl/iflat_multimap.h b/lib/etl/iflat_multimap.h
new file mode 100644
index 0000000..e5fa864
--- /dev/null
+++ b/lib/etl/iflat_multimap.h
@@ -0,0 +1,530 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2015 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_IFLAT_MULTIMAP__
+#define __ETL_IFLAT_MULTIMAP__
+#define __ETL_IN_IFLAT_MULTIMAP_H__
+
+#include <iterator>
+#include <algorithm>
+#include <functional>
+#include <utility>
+#include <stddef.h>
+
+#include "private/flat_multimap_base.h"
+#include "type_traits.h"
+#include "parameter_type.h"
+#include "ivector.h"
+#include "error_handler.h"
+
+namespace etl
+{
+ //***************************************************************************
+ /// The base class for specifically sized flat_multimaps.
+ /// Can be used as a reference type for all flat_multimaps containing a specific type.
+ ///\ingroup flat_multimap
+ //***************************************************************************
+ template <typename TKey, typename TMapped, typename TKeyCompare = std::less<TKey> >
+ class iflat_multimap : public flat_multimap_base
+ {
+ public:
+
+ typedef std::pair<TKey, TMapped> value_type;
+
+ private:
+
+ typedef etl::ivector<value_type> buffer_t;
+
+ public:
+
+ typedef TKey key_type;
+ typedef TMapped mapped_type;
+ typedef TKeyCompare key_compare;
+ typedef value_type& reference;
+ typedef const value_type& const_reference;
+ typedef value_type* pointer;
+ typedef const value_type* const_pointer;
+ typedef typename buffer_t::iterator iterator;
+ typedef typename buffer_t::const_iterator const_iterator;
+ typedef typename buffer_t::reverse_iterator reverse_iterator;
+ typedef typename buffer_t::const_reverse_iterator const_reverse_iterator;
+ typedef size_t size_type;
+ typedef typename std::iterator_traits<iterator>::difference_type difference_type;
+
+ protected:
+
+ typedef typename parameter_type<TKey>::type key_value_parameter_t;
+
+ private:
+
+ //*********************************************************************
+ /// How to compare elements and keys.
+ //*********************************************************************
+ class compare
+ {
+ public:
+
+ bool operator ()(const value_type& element, key_type key) const
+ {
+ return key_compare()(element.first, key);
+ }
+
+ bool operator ()(key_type key, const value_type& element) const
+ {
+ return key_compare()(key, element.first);
+ }
+ };
+
+ public:
+
+ //*********************************************************************
+ /// Returns an iterator to the beginning of the flat_multimap.
+ ///\return An iterator to the beginning of the flat_multimap.
+ //*********************************************************************
+ iterator begin()
+ {
+ return buffer.begin();
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the beginning of the flat_multimap.
+ ///\return A const iterator to the beginning of the flat_multimap.
+ //*********************************************************************
+ const_iterator begin() const
+ {
+ return buffer.begin();
+ }
+
+ //*********************************************************************
+ /// Returns an iterator to the end of the flat_multimap.
+ ///\return An iterator to the end of the flat_multimap.
+ //*********************************************************************
+ iterator end()
+ {
+ return buffer.end();
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the end of the flat_multimap.
+ ///\return A const iterator to the end of the flat_multimap.
+ //*********************************************************************
+ const_iterator end() const
+ {
+ return buffer.end();
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the beginning of the flat_multimap.
+ ///\return A const iterator to the beginning of the flat_multimap.
+ //*********************************************************************
+ const_iterator cbegin() const
+ {
+ return buffer.cbegin();
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the end of the flat_multimap.
+ ///\return A const iterator to the end of the flat_multimap.
+ //*********************************************************************
+ const_iterator cend() const
+ {
+ return buffer.cend();
+ }
+
+ //*********************************************************************
+ /// Returns an reverse iterator to the reverse beginning of the flat_multimap.
+ ///\return Iterator to the reverse beginning of the flat_multimap.
+ //*********************************************************************
+ reverse_iterator rbegin()
+ {
+ return buffer.rbegin();
+ }
+
+ //*********************************************************************
+ /// Returns a const reverse iterator to the reverse beginning of the flat_multimap.
+ ///\return Const iterator to the reverse beginning of the flat_multimap.
+ //*********************************************************************
+ const_reverse_iterator rbegin() const
+ {
+ return buffer.rbegin();
+ }
+
+ //*********************************************************************
+ /// Returns a reverse iterator to the end + 1 of the flat_multimap.
+ ///\return Reverse iterator to the end + 1 of the flat_multimap.
+ //*********************************************************************
+ reverse_iterator rend()
+ {
+ return buffer.rend();
+ }
+
+ //*********************************************************************
+ /// Returns a const reverse iterator to the end + 1 of the flat_multimap.
+ ///\return Const reverse iterator to the end + 1 of the flat_multimap.
+ //*********************************************************************
+ const_reverse_iterator rend() const
+ {
+ return buffer.rend();
+ }
+
+ //*********************************************************************
+ /// Returns a const reverse iterator to the reverse beginning of the flat_multimap.
+ ///\return Const reverse iterator to the reverse beginning of the flat_multimap.
+ //*********************************************************************
+ const_reverse_iterator crbegin() const
+ {
+ return buffer.crbegin();
+ }
+
+ //*********************************************************************
+ /// Returns a const reverse iterator to the end + 1 of the flat_multimap.
+ ///\return Const reverse iterator to the end + 1 of the flat_multimap.
+ //*********************************************************************
+ const_reverse_iterator crend() const
+ {
+ return buffer.crend();
+ }
+
+ //*********************************************************************
+ /// Assigns values to the flat_multimap.
+ /// If asserts or exceptions are enabled, emits flat_multimap_full if the flat_multimap does not have enough free space.
+ /// If asserts or exceptions are enabled, emits flat_multimap_iterator if the iterators are reversed.
+ ///\param first The iterator to the first element.
+ ///\param last The iterator to the last element + 1.
+ //*********************************************************************
+ template <typename TIterator>
+ void assign(TIterator first, TIterator last)
+ {
+#ifdef _DEBUG
+ difference_type count = std::distance(first, last);
+ ETL_ASSERT(count <= difference_type(capacity()), ETL_ERROR(flat_multimap_full));
+#endif
+
+ clear();
+
+ while (first != last)
+ {
+ insert(*first++);
+ }
+ }
+
+ //*********************************************************************
+ /// Inserts a value to the flat_multimap.
+ /// If asserts or exceptions are enabled, emits flat_multimap_full if the flat_multimap is already full.
+ ///\param value The value to insert.
+ //*********************************************************************
+ std::pair<iterator, bool> insert(const value_type& value)
+ {
+ ETL_ASSERT(!buffer.full(), ETL_ERROR(flat_multimap_full));
+
+ std::pair<iterator, bool> result(end(), false);
+
+ iterator i_element = lower_bound(value.first);
+
+ if (i_element == end())
+ {
+ // At the end.
+ buffer.push_back(value);
+ result.first = end() - 1;
+ result.second = true;
+ }
+ else
+ {
+ // Not at the end.
+ buffer.insert(i_element, value);
+ result.first = i_element;
+ result.second = true;
+ }
+
+ return result;
+ }
+
+ //*********************************************************************
+ /// Inserts a value to the flast_multi.
+ /// If asserts or exceptions are enabled, emits flat_map_full if the flat_map is already full.
+ ///\param position The position to insert at.
+ ///\param value The value to insert.
+ //*********************************************************************
+ iterator insert(iterator position, const value_type& value)
+ {
+ return insert(value).first;
+ }
+
+ //*********************************************************************
+ /// Inserts a range of values to the flat_multimap.
+ /// If asserts or exceptions are enabled, emits flat_multimap_full if the flat_multimap does not have enough free space.
+ ///\param position The position to insert at.
+ ///\param first The first element to add.
+ ///\param last The last + 1 element to add.
+ //*********************************************************************
+ template <class TIterator>
+ void insert(TIterator first, TIterator last)
+ {
+ while (first != last)
+ {
+ insert(*first++);
+ }
+ }
+
+ //*********************************************************************
+ /// Erases an element.
+ ///\param key The key to erase.
+ ///\return The number of elements erased. 0 or 1.
+ //*********************************************************************
+ size_t erase(key_value_parameter_t key)
+ {
+ std::pair<iterator, iterator> range = equal_range(key);
+
+ if (range.first == end())
+ {
+ return 0;
+ }
+ else
+ {
+ size_t count = std::distance(range.first, range.second);
+ erase(range.first, range.second);
+ return count;
+ }
+ }
+
+ //*********************************************************************
+ /// Erases an element.
+ ///\param i_element Iterator to the element.
+ //*********************************************************************
+ void erase(iterator i_element)
+ {
+ buffer.erase(i_element);
+ }
+
+ //*********************************************************************
+ /// Erases a range of elements.
+ /// The range includes all the elements between first and last, including the
+ /// element pointed by first, but not the one pointed by last.
+ ///\param first Iterator to the first element.
+ ///\param last Iterator to the last element.
+ //*********************************************************************
+ void erase(iterator first, iterator last)
+ {
+ buffer.erase(first, last);
+ }
+
+ //*************************************************************************
+ /// Clears the flat_multimap.
+ //*************************************************************************
+ void clear()
+ {
+ buffer.clear();
+ }
+
+ //*********************************************************************
+ /// Finds an element.
+ ///\param key The key to search for.
+ ///\return An iterator pointing to the element or end() if not found.
+ //*********************************************************************
+ iterator find(key_value_parameter_t key)
+ {
+ iterator itr = lower_bound(key);
+
+ if (itr != end())
+ {
+ if (!key_compare()(itr->first, key) && !key_compare()(key, itr->first))
+ {
+ return itr;
+ }
+ else
+ {
+ return end();
+ }
+ }
+
+ return end();
+ }
+
+ //*********************************************************************
+ /// Finds an element.
+ ///\param key The key to search for.
+ ///\return An iterator pointing to the element or end() if not found.
+ //*********************************************************************
+ const_iterator find(key_value_parameter_t key) const
+ {
+ const_iterator itr = lower_bound(key);
+
+ if (itr != end())
+ {
+ if (!key_compare()(itr->first, key) && !key_compare()(key, itr->first))
+ {
+ return itr;
+ }
+ else
+ {
+ return end();
+ }
+ }
+
+ return end();
+ }
+
+ //*********************************************************************
+ /// Counts an element.
+ ///\param key The key to search for.
+ ///\return 1 if the key exists, otherwise 0.
+ //*********************************************************************
+ size_t count(key_value_parameter_t key) const
+ {
+ std::pair<const_iterator, const_iterator> range = equal_range(key);
+
+ return std::distance(range.first, range.second);
+ }
+
+ //*********************************************************************
+ /// Finds the lower bound of a key
+ ///\param key The key to search for.
+ ///\return An iterator.
+ //*********************************************************************
+ iterator lower_bound(key_value_parameter_t key)
+ {
+ return std::lower_bound(begin(), end(), key, compare());
+ }
+
+ //*********************************************************************
+ /// Finds the lower bound of a key
+ ///\param key The key to search for.
+ ///\return An iterator.
+ //*********************************************************************
+ const_iterator lower_bound(key_value_parameter_t key) const
+ {
+ return std::lower_bound(cbegin(), cend(), key, compare());
+ }
+
+ //*********************************************************************
+ /// Finds the upper bound of a key
+ ///\param key The key to search for.
+ ///\return An iterator.
+ //*********************************************************************
+ iterator upper_bound(key_value_parameter_t key)
+ {
+ return std::upper_bound(begin(), end(), key, compare());
+ }
+
+ //*********************************************************************
+ /// Finds the upper bound of a key
+ ///\param key The key to search for.
+ ///\return An iterator.
+ //*********************************************************************
+ const_iterator upper_bound(key_value_parameter_t key) const
+ {
+ return std::upper_bound(begin(), end(), key, compare());
+ }
+
+ //*********************************************************************
+ /// Finds the range of equal elements of a key
+ ///\param key The key to search for.
+ ///\return An iterator pair.
+ //*********************************************************************
+ std::pair<iterator, iterator> equal_range(key_value_parameter_t key)
+ {
+ iterator i_lower = std::lower_bound(begin(), end(), key, compare());
+
+ return std::make_pair(i_lower, std::upper_bound(i_lower, end(), key, compare()));
+ }
+
+ //*********************************************************************
+ /// Finds the range of equal elements of a key
+ ///\param key The key to search for.
+ ///\return An iterator pair.
+ //*********************************************************************
+ std::pair<const_iterator, const_iterator> equal_range(key_value_parameter_t key) const
+ {
+ const_iterator i_lower = std::lower_bound(cbegin(), cend(), key, compare());
+
+ return std::make_pair(i_lower, std::upper_bound(i_lower, cend(), key, compare()));
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ iflat_multimap& operator = (const iflat_multimap& rhs)
+ {
+ if (&rhs != this)
+ {
+ assign(rhs.cbegin(), rhs.cend());
+ }
+
+ return *this;
+ }
+
+ protected:
+
+ //*********************************************************************
+ /// Constructor.
+ //*********************************************************************
+ iflat_multimap(buffer_t& buffer)
+ : flat_multimap_base(buffer),
+ buffer(buffer)
+ {
+ }
+
+ private:
+
+ // Disable copy construction.
+ iflat_multimap(const iflat_multimap&);
+
+ buffer_t& buffer;
+ };
+
+ //***************************************************************************
+ /// Equal operator.
+ ///\param lhs Reference to the first flat_multimap.
+ ///\param rhs Reference to the second flat_multimap.
+ ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
+ ///\ingroup flat_multimap
+ //***************************************************************************
+ template <typename TKey, typename TMapped, typename TKeyCompare>
+ bool operator ==(const etl::iflat_multimap<TKey, TMapped, TKeyCompare>& lhs, const etl::iflat_multimap<TKey, TMapped, TKeyCompare>& rhs)
+ {
+ return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin());
+ }
+
+ //***************************************************************************
+ /// Not equal operator.
+ ///\param lhs Reference to the first flat_multimap.
+ ///\param rhs Reference to the second flat_multimap.
+ ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
+ ///\ingroup flat_multimap
+ //***************************************************************************
+ template <typename TKey, typename TMapped, typename TKeyCompare>
+ bool operator !=(const etl::iflat_multimap<TKey, TMapped, TKeyCompare>& lhs, const etl::iflat_multimap<TKey, TMapped, TKeyCompare>& rhs)
+ {
+ return !(lhs == rhs);
+ }
+}
+
+#undef __ETL_IN_IFLAT_MULTIMAP_H__
+#endif
diff --git a/lib/etl/iflat_multiset.h b/lib/etl/iflat_multiset.h
new file mode 100644
index 0000000..135511c
--- /dev/null
+++ b/lib/etl/iflat_multiset.h
@@ -0,0 +1,502 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2015 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_IFLAT_MULTISET__
+#define __ETL_IFLAT_MULTISET__
+#define __ETL_IN_IFLAT_MULTISET_H__
+
+#include <iterator>
+#include <algorithm>
+#include <functional>
+#include <utility>
+#include <stddef.h>
+
+#include "private/flat_multiset_base.h"
+#include "type_traits.h"
+#include "parameter_type.h"
+#include "ivector.h"
+#include "error_handler.h"
+
+namespace etl
+{
+ //***************************************************************************
+ /// The base class for specifically sized flat_multisets.
+ /// Can be used as a reference type for all flat_multisets containing a specific type.
+ ///\ingroup flat_multiset
+ //***************************************************************************
+ template <typename T, typename TKeyCompare = std::less<T> >
+ class iflat_multiset : public flat_multiset_base
+ {
+ private:
+
+ typedef etl::ivector<T> buffer_t;
+
+ public:
+
+ typedef T key_type;
+ typedef T value_type;
+ typedef TKeyCompare key_compare;
+ typedef value_type& reference;
+ typedef const value_type& const_reference;
+ typedef value_type* pointer;
+ typedef const value_type* const_pointer;
+ typedef typename buffer_t::iterator iterator;
+ typedef typename buffer_t::const_iterator const_iterator;
+ typedef typename buffer_t::reverse_iterator reverse_iterator;
+ typedef typename buffer_t::const_reverse_iterator const_reverse_iterator;
+ typedef size_t size_type;
+ typedef typename std::iterator_traits<iterator>::difference_type difference_type;
+
+ protected:
+
+ typedef typename parameter_type<T>::type parameter_t;
+
+ public:
+
+ //*********************************************************************
+ /// Returns an iterator to the beginning of the flat_multiset.
+ ///\return An iterator to the beginning of the flat_multiset.
+ //*********************************************************************
+ iterator begin()
+ {
+ return buffer.begin();
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the beginning of the flat_multiset.
+ ///\return A const iterator to the beginning of the flat_multiset.
+ //*********************************************************************
+ const_iterator begin() const
+ {
+ return buffer.begin();
+ }
+
+ //*********************************************************************
+ /// Returns an iterator to the end of the flat_multiset.
+ ///\return An iterator to the end of the flat_multiset.
+ //*********************************************************************
+ iterator end()
+ {
+ return buffer.end();
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the end of the flat_multiset.
+ ///\return A const iterator to the end of the flat_multiset.
+ //*********************************************************************
+ const_iterator end() const
+ {
+ return buffer.end();
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the beginning of the flat_multiset.
+ ///\return A const iterator to the beginning of the flat_multiset.
+ //*********************************************************************
+ const_iterator cbegin() const
+ {
+ return buffer.cbegin();
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the end of the flat_multiset.
+ ///\return A const iterator to the end of the flat_multiset.
+ //*********************************************************************
+ const_iterator cend() const
+ {
+ return buffer.cend();
+ }
+
+ //*********************************************************************
+ /// Returns an reverse iterator to the reverse beginning of the flat_multiset.
+ ///\return Iterator to the reverse beginning of the flat_multiset.
+ //*********************************************************************
+ reverse_iterator rbegin()
+ {
+ return buffer.rbegin();
+ }
+
+ //*********************************************************************
+ /// Returns a const reverse iterator to the reverse beginning of the flat_multiset.
+ ///\return Const iterator to the reverse beginning of the flat_multiset.
+ //*********************************************************************
+ const_reverse_iterator rbegin() const
+ {
+ return buffer.rbegin();
+ }
+
+ //*********************************************************************
+ /// Returns a reverse iterator to the end + 1 of the flat_multiset.
+ ///\return Reverse iterator to the end + 1 of the flat_multiset.
+ //*********************************************************************
+ reverse_iterator rend()
+ {
+ return buffer.rend();
+ }
+
+ //*********************************************************************
+ /// Returns a const reverse iterator to the end + 1 of the flat_multiset.
+ ///\return Const reverse iterator to the end + 1 of the flat_multiset.
+ //*********************************************************************
+ const_reverse_iterator rend() const
+ {
+ return buffer.rend();
+ }
+
+ //*********************************************************************
+ /// Returns a const reverse iterator to the reverse beginning of the flat_multiset.
+ ///\return Const reverse iterator to the reverse beginning of the flat_multiset.
+ //*********************************************************************
+ const_reverse_iterator crbegin() const
+ {
+ return buffer.crbegin();
+ }
+
+ //*********************************************************************
+ /// Returns a const reverse iterator to the end + 1 of the flat_multiset.
+ ///\return Const reverse iterator to the end + 1 of the flat_multiset.
+ //*********************************************************************
+ const_reverse_iterator crend() const
+ {
+ return buffer.crend();
+ }
+
+ //*********************************************************************
+ /// Assigns values to the flat_multiset.
+ /// If asserts or exceptions are enabled, emits flat_multiset_full if the flat_multiset does not have enough free space.
+ /// If asserts or exceptions are enabled, emits flat_multiset_iterator if the iterators are reversed.
+ ///\param first The iterator to the first element.
+ ///\param last The iterator to the last element + 1.
+ //*********************************************************************
+ template <typename TIterator>
+ void assign(TIterator first, TIterator last)
+ {
+#ifdef _DEBUG
+ difference_type count = std::distance(first, last);
+ ETL_ASSERT(count <= difference_type(capacity()), ETL_ERROR(flat_multiset_full));
+#endif
+
+ clear();
+
+ while (first != last)
+ {
+ insert(*first++);
+ }
+ }
+
+ //*********************************************************************
+ /// Inserts a value to the flat_multiset.
+ /// If asserts or exceptions are enabled, emits flat_multiset_full if the flat_multiset is already full.
+ ///\param value The value to insert.
+ //*********************************************************************
+ std::pair<iterator, bool> insert(parameter_t value)
+ {
+ std::pair<iterator, bool> result(end(), false);
+
+ ETL_ASSERT(!buffer.full(), ETL_ERROR(flat_multiset_full));
+
+ iterator i_element = std::lower_bound(begin(), end(), value, TKeyCompare());
+
+ if (i_element == end())
+ {
+ // At the end.
+ buffer.push_back(value);
+ result.first = end() - 1;
+ result.second = true;
+ }
+ else
+ {
+ // Not at the end.
+ buffer.insert(i_element, value);
+ result.first = i_element;
+ result.second = true;
+ }
+
+ return result;
+ }
+
+ //*********************************************************************
+ /// Inserts a value to the flat_multiset.
+ /// If asserts or exceptions are enabled, emits flat_multiset_full if the flat_multiset is already full.
+ ///\param position The position to insert at.
+ ///\param value The value to insert.
+ //*********************************************************************
+ iterator insert(iterator position, parameter_t value)
+ {
+ return insert(value).first;
+ }
+
+ //*********************************************************************
+ /// Inserts a range of values to the flat_multiset.
+ /// If asserts or exceptions are enabled, emits flat_multiset_full if the flat_multiset does not have enough free space.
+ ///\param position The position to insert at.
+ ///\param first The first element to add.
+ ///\param last The last + 1 element to add.
+ //*********************************************************************
+ template <class TIterator>
+ void insert(TIterator first, TIterator last)
+ {
+ while (first != last)
+ {
+ insert(*first++);
+ }
+ }
+
+ //*********************************************************************
+ /// Erases an element.
+ ///\param key The key to erase.
+ ///\return The number of elements erased. 0 or 1.
+ //*********************************************************************
+ size_t erase(parameter_t key)
+ {
+ std::pair<iterator, iterator> range = equal_range(key);
+
+ if (range.first == end())
+ {
+ return 0;
+ }
+ else
+ {
+ size_t count = std::distance(range.first, range.second);
+ erase(range.first, range.second);
+ return count;
+ }
+ }
+
+ //*********************************************************************
+ /// Erases an element.
+ ///\param i_element Iterator to the element.
+ //*********************************************************************
+ void erase(iterator i_element)
+ {
+ buffer.erase(i_element);
+ }
+
+ //*********************************************************************
+ /// Erases a range of elements.
+ /// The range includes all the elements between first and last, including the
+ /// element pointed by first, but not the one pointed by last.
+ ///\param first Iterator to the first element.
+ ///\param last Iterator to the last element.
+ //*********************************************************************
+ void erase(iterator first, iterator last)
+ {
+ buffer.erase(first, last);
+ }
+
+ //*************************************************************************
+ /// Clears the flat_multiset.
+ //*************************************************************************
+ void clear()
+ {
+ buffer.clear();
+ }
+
+ //*********************************************************************
+ /// Finds an element.
+ ///\param key The key to search for.
+ ///\return An iterator pointing to the element or end() if not found.
+ //*********************************************************************
+ iterator find(parameter_t key)
+ {
+ iterator itr = std::lower_bound(begin(), end(), key, TKeyCompare());
+
+ if (itr != end())
+ {
+ if (!key_compare()(*itr, key) && !key_compare()(key, *itr))
+ {
+ return itr;
+ }
+ else
+ {
+ return end();
+ }
+ }
+
+ return end();
+ }
+
+ //*********************************************************************
+ /// Finds an element.
+ ///\param key The key to search for.
+ ///\return An iterator pointing to the element or end() if not found.
+ //*********************************************************************
+ const_iterator find(parameter_t key) const
+ {
+ const_iterator itr = std::lower_bound(begin(), end(), key, TKeyCompare());
+
+ if (itr != end())
+ {
+ if (!key_compare()(*itr, key) && !key_compare()(key, *itr))
+ {
+ return itr;
+ }
+ else
+ {
+ return end();
+ }
+ }
+
+ return end();
+ }
+
+ //*********************************************************************
+ /// Counts an element.
+ ///\param key The key to search for.
+ ///\return 1 if the key exists, otherwise 0.
+ //*********************************************************************
+ size_t count(parameter_t key) const
+ {
+ std::pair<const_iterator, const_iterator> range = equal_range(key);
+
+ return std::distance(range.first, range.second);
+ }
+
+ //*********************************************************************
+ /// Finds the lower bound of a key
+ ///\param key The key to search for.
+ ///\return An iterator.
+ //*********************************************************************
+ iterator lower_bound(parameter_t key)
+ {
+ return std::lower_bound(begin(), end(), key, TKeyCompare());
+ }
+
+ //*********************************************************************
+ /// Finds the lower bound of a key
+ ///\param key The key to search for.
+ ///\return An iterator.
+ //*********************************************************************
+ const_iterator lower_bound(parameter_t key) const
+ {
+ return std::lower_bound(cbegin(), cend(), key, TKeyCompare());
+ }
+
+ //*********************************************************************
+ /// Finds the upper bound of a key
+ ///\param key The key to search for.
+ ///\return An iterator.
+ //*********************************************************************
+ iterator upper_bound(parameter_t key)
+ {
+ return std::upper_bound(begin(), end(), key, TKeyCompare());
+ }
+
+ //*********************************************************************
+ /// Finds the upper bound of a key
+ ///\param key The key to search for.
+ ///\return An iterator.
+ //*********************************************************************
+ const_iterator upper_bound(parameter_t key) const
+ {
+ return std::upper_bound(cbegin(), cend(), key, TKeyCompare());
+ }
+
+ //*********************************************************************
+ /// Finds the range of equal elements of a key
+ ///\param key The key to search for.
+ ///\return An iterator pair.
+ //*********************************************************************
+ std::pair<iterator, iterator> equal_range(parameter_t key)
+ {
+ return std::equal_range(begin(), end(), key, TKeyCompare());
+ }
+
+ //*********************************************************************
+ /// Finds the range of equal elements of a key
+ ///\param key The key to search for.
+ ///\return An iterator pair.
+ //*********************************************************************
+ std::pair<const_iterator, const_iterator> equal_range(parameter_t key) const
+ {
+ return std::equal_range(cbegin(), cend(), key, TKeyCompare());
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ iflat_multiset& operator = (const iflat_multiset& rhs)
+ {
+ if (&rhs != this)
+ {
+ assign(rhs.cbegin(), rhs.cend());
+ }
+
+ return *this;
+ }
+
+ protected:
+
+ //*********************************************************************
+ /// Constructor.
+ //*********************************************************************
+ iflat_multiset(buffer_t& buffer)
+ : flat_multiset_base(buffer),
+ buffer(buffer)
+ {
+ }
+
+ private:
+
+ // Disable copy construction.
+ iflat_multiset(const iflat_multiset&);
+
+ buffer_t& buffer;
+ };
+
+ //***************************************************************************
+ /// Equal operator.
+ ///\param lhs Reference to the first flat_multiset.
+ ///\param rhs Reference to the second flat_multiset.
+ ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
+ ///\ingroup flat_multiset
+ //***************************************************************************
+ template <typename T, typename TKeyCompare>
+ bool operator ==(const etl::iflat_multiset<T, TKeyCompare>& lhs, const etl::iflat_multiset<T, TKeyCompare>& rhs)
+ {
+ return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin());
+ }
+
+ //***************************************************************************
+ /// Not equal operator.
+ ///\param lhs Reference to the first flat_multiset.
+ ///\param rhs Reference to the second flat_multiset.
+ ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
+ ///\ingroup flat_multiset
+ //***************************************************************************
+ template <typename T, typename TKeyCompare>
+ bool operator !=(const etl::iflat_multiset<T, TKeyCompare>& lhs, const etl::iflat_multiset<T, TKeyCompare>& rhs)
+ {
+ return !(lhs == rhs);
+ }
+}
+
+#undef __ETL_IN_IFLAT_MULTISET_H__
+#endif
diff --git a/lib/etl/iflat_set.h b/lib/etl/iflat_set.h
new file mode 100644
index 0000000..55ca571
--- /dev/null
+++ b/lib/etl/iflat_set.h
@@ -0,0 +1,508 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2015 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_IFLAT_SET__
+#define __ETL_IFLAT_SET__
+#define __ETL_IN_IFLAT_SET_H__
+
+#include <iterator>
+#include <algorithm>
+#include <functional>
+#include <utility>
+#include <stddef.h>
+
+#include "private/flat_set_base.h"
+#include "type_traits.h"
+#include "parameter_type.h"
+#include "ivector.h"
+#include "error_handler.h"
+
+namespace etl
+{
+ //***************************************************************************
+ /// The base class for specifically sized flat_sets.
+ /// Can be used as a reference type for all flat_sets containing a specific type.
+ ///\ingroup flat_set
+ //***************************************************************************
+ template <typename T, typename TKeyCompare = std::less<T> >
+ class iflat_set : public flat_set_base
+ {
+ private:
+
+ typedef etl::ivector<T> buffer_t;
+
+ public:
+
+ typedef T key_type;
+ typedef T value_type;
+ typedef TKeyCompare key_compare;
+ typedef value_type& reference;
+ typedef const value_type& const_reference;
+ typedef value_type* pointer;
+ typedef const value_type* const_pointer;
+ typedef typename buffer_t::iterator iterator;
+ typedef typename buffer_t::const_iterator const_iterator;
+ typedef typename buffer_t::reverse_iterator reverse_iterator;
+ typedef typename buffer_t::const_reverse_iterator const_reverse_iterator;
+ typedef size_t size_type;
+ typedef typename std::iterator_traits<iterator>::difference_type difference_type;
+
+ protected:
+
+ typedef typename parameter_type<T>::type parameter_t;
+
+ public:
+
+ //*********************************************************************
+ /// Returns an iterator to the beginning of the flat_set.
+ ///\return An iterator to the beginning of the flat_set.
+ //*********************************************************************
+ iterator begin()
+ {
+ return buffer.begin();
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the beginning of the flat_set.
+ ///\return A const iterator to the beginning of the flat_set.
+ //*********************************************************************
+ const_iterator begin() const
+ {
+ return buffer.begin();
+ }
+
+ //*********************************************************************
+ /// Returns an iterator to the end of the flat_set.
+ ///\return An iterator to the end of the flat_set.
+ //*********************************************************************
+ iterator end()
+ {
+ return buffer.end();
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the end of the flat_set.
+ ///\return A const iterator to the end of the flat_set.
+ //*********************************************************************
+ const_iterator end() const
+ {
+ return buffer.end();
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the beginning of the flat_set.
+ ///\return A const iterator to the beginning of the flat_set.
+ //*********************************************************************
+ const_iterator cbegin() const
+ {
+ return buffer.cbegin();
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the end of the flat_set.
+ ///\return A const iterator to the end of the flat_set.
+ //*********************************************************************
+ const_iterator cend() const
+ {
+ return buffer.cend();
+ }
+
+ //*********************************************************************
+ /// Returns an reverse iterator to the reverse beginning of the flat_set.
+ ///\return Iterator to the reverse beginning of the flat_set.
+ //*********************************************************************
+ reverse_iterator rbegin()
+ {
+ return buffer.rbegin();
+ }
+
+ //*********************************************************************
+ /// Returns a const reverse iterator to the reverse beginning of the flat_set.
+ ///\return Const iterator to the reverse beginning of the flat_set.
+ //*********************************************************************
+ const_reverse_iterator rbegin() const
+ {
+ return buffer.rbegin();
+ }
+
+ //*********************************************************************
+ /// Returns a reverse iterator to the end + 1 of the flat_set.
+ ///\return Reverse iterator to the end + 1 of the flat_set.
+ //*********************************************************************
+ reverse_iterator rend()
+ {
+ return buffer.rend();
+ }
+
+ //*********************************************************************
+ /// Returns a const reverse iterator to the end + 1 of the flat_set.
+ ///\return Const reverse iterator to the end + 1 of the flat_set.
+ //*********************************************************************
+ const_reverse_iterator rend() const
+ {
+ return buffer.rend();
+ }
+
+ //*********************************************************************
+ /// Returns a const reverse iterator to the reverse beginning of the flat_set.
+ ///\return Const reverse iterator to the reverse beginning of the flat_set.
+ //*********************************************************************
+ const_reverse_iterator crbegin() const
+ {
+ return buffer.crbegin();
+ }
+
+ //*********************************************************************
+ /// Returns a const reverse iterator to the end + 1 of the flat_set.
+ ///\return Const reverse iterator to the end + 1 of the flat_set.
+ //*********************************************************************
+ const_reverse_iterator crend() const
+ {
+ return buffer.crend();
+ }
+
+ //*********************************************************************
+ /// Assigns values to the flat_set.
+ /// If asserts or exceptions are enabled, emits flat_set_full if the flat_set does not have enough free space.
+ /// If asserts or exceptions are enabled, emits flat_set_iterator if the iterators are reversed.
+ ///\param first The iterator to the first element.
+ ///\param last The iterator to the last element + 1.
+ //*********************************************************************
+ template <typename TIterator>
+ void assign(TIterator first, TIterator last)
+ {
+#ifdef _DEBUG
+ difference_type count = std::distance(first, last);
+ ETL_ASSERT(count <= difference_type(capacity()), ETL_ERROR(flat_set_full));
+#endif
+
+ clear();
+
+ while (first != last)
+ {
+ insert(*first++);
+ }
+ }
+
+ //*********************************************************************
+ /// Inserts a value to the flat_set.
+ /// If asserts or exceptions are enabled, emits flat_set_full if the flat_set is already full.
+ ///\param value The value to insert.
+ //*********************************************************************
+ std::pair<iterator, bool> insert(parameter_t value)
+ {
+ std::pair<iterator, bool> result(end(), false);
+
+ ETL_ASSERT(!buffer.full(), ETL_ERROR(flat_set_full));
+
+ iterator i_element = std::lower_bound(begin(), end(), value, TKeyCompare());
+
+ if (i_element == end())
+ {
+ // At the end. Doesn't exist.
+ buffer.push_back(value);
+ result.first = end() - 1;
+ result.second = true;
+ }
+ else
+ {
+ // Not at the end.
+ // Does not exist already?
+ if (*i_element != value)
+ {
+ buffer.insert(i_element, value);
+ result.first = i_element;
+ result.second = true;
+ }
+ else
+ {
+ result.first = i_element;
+ result.second = false;
+ }
+ }
+
+ return result;
+ }
+
+ //*********************************************************************
+ /// Inserts a value to the flat_set.
+ /// If asserts or exceptions are enabled, emits flat_set_full if the flat_set is already full.
+ ///\param position The position to insert at.
+ ///\param value The value to insert.
+ //*********************************************************************
+ iterator insert(iterator position, parameter_t value)
+ {
+ return insert(value).first;
+ }
+
+ //*********************************************************************
+ /// Inserts a range of values to the flat_set.
+ /// If asserts or exceptions are enabled, emits flat_set_full if the flat_set does not have enough free space.
+ ///\param position The position to insert at.
+ ///\param first The first element to add.
+ ///\param last The last + 1 element to add.
+ //*********************************************************************
+ template <class TIterator>
+ void insert(TIterator first, TIterator last)
+ {
+ while (first != last)
+ {
+ insert(*first++);
+ }
+ }
+
+ //*********************************************************************
+ /// Erases an element.
+ ///\param key The key to erase.
+ ///\return The number of elements erased. 0 or 1.
+ //*********************************************************************
+ size_t erase(parameter_t key)
+ {
+ iterator i_element = find(key);
+
+ if (i_element == end())
+ {
+ return 0;
+ }
+ else
+ {
+ buffer.erase(i_element);
+ return 1;
+ }
+ }
+
+ //*********************************************************************
+ /// Erases an element.
+ ///\param i_element Iterator to the element.
+ //*********************************************************************
+ void erase(iterator i_element)
+ {
+ buffer.erase(i_element);
+ }
+
+ //*********************************************************************
+ /// Erases a range of elements.
+ /// The range includes all the elements between first and last, including the
+ /// element pointed by first, but not the one pointed by last.
+ ///\param first Iterator to the first element.
+ ///\param last Iterator to the last element.
+ //*********************************************************************
+ void erase(iterator first, iterator last)
+ {
+ buffer.erase(first, last);
+ }
+
+ //*************************************************************************
+ /// Clears the flat_set.
+ //*************************************************************************
+ void clear()
+ {
+ buffer.clear();
+ }
+
+ //*********************************************************************
+ /// Finds an element.
+ ///\param key The key to search for.
+ ///\return An iterator pointing to the element or end() if not found.
+ //*********************************************************************
+ iterator find(parameter_t key)
+ {
+ iterator itr = std::lower_bound(begin(), end(), key, TKeyCompare());
+
+ if (itr != end())
+ {
+ if (!key_compare()(*itr, key) && !key_compare()(key, *itr))
+ {
+ return itr;
+ }
+ else
+ {
+ return end();
+ }
+ }
+
+ return end();
+ }
+
+ //*********************************************************************
+ /// Finds an element.
+ ///\param key The key to search for.
+ ///\return An iterator pointing to the element or end() if not found.
+ //*********************************************************************
+ const_iterator find(parameter_t key) const
+ {
+ const_iterator itr = std::lower_bound(begin(), end(), key, TKeyCompare());
+
+ if (itr != end())
+ {
+ if (!key_compare()(*itr, key) && !key_compare()(key, *itr))
+ {
+ return itr;
+ }
+ else
+ {
+ return end();
+ }
+ }
+
+ return end();
+ }
+
+ //*********************************************************************
+ /// Counts an element.
+ ///\param key The key to search for.
+ ///\return 1 if the key exists, otherwise 0.
+ //*********************************************************************
+ size_t count(parameter_t key) const
+ {
+ return (find(key) == end()) ? 0 : 1;
+ }
+
+ //*********************************************************************
+ /// Finds the lower bound of a key
+ ///\param key The key to search for.
+ ///\return An iterator.
+ //*********************************************************************
+ iterator lower_bound(parameter_t key)
+ {
+ return std::lower_bound(begin(), end(), key, TKeyCompare());
+ }
+
+ //*********************************************************************
+ /// Finds the lower bound of a key
+ ///\param key The key to search for.
+ ///\return An iterator.
+ //*********************************************************************
+ const_iterator lower_bound(parameter_t key) const
+ {
+ return std::lower_bound(cbegin(), cend(), key, TKeyCompare());
+ }
+
+ //*********************************************************************
+ /// Finds the upper bound of a key
+ ///\param key The key to search for.
+ ///\return An iterator.
+ //*********************************************************************
+ iterator upper_bound(parameter_t key)
+ {
+ return std::upper_bound(begin(), end(), key, TKeyCompare());
+ }
+
+ //*********************************************************************
+ /// Finds the upper bound of a key
+ ///\param key The key to search for.
+ ///\return An iterator.
+ //*********************************************************************
+ const_iterator upper_bound(parameter_t key) const
+ {
+ return std::upper_bound(cbegin(), cend(), key, TKeyCompare());
+ }
+
+ //*********************************************************************
+ /// Finds the range of equal elements of a key
+ ///\param key The key to search for.
+ ///\return An iterator pair.
+ //*********************************************************************
+ std::pair<iterator, iterator> equal_range(parameter_t key)
+ {
+ return std::equal_range(begin(), end(), key, TKeyCompare());
+ }
+
+ //*********************************************************************
+ /// Finds the range of equal elements of a key
+ ///\param key The key to search for.
+ ///\return An iterator pair.
+ //*********************************************************************
+ std::pair<const_iterator, const_iterator> equal_range(parameter_t key) const
+ {
+ return std::upper_bound(cbegin(), cend(), key, TKeyCompare());
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ iflat_set& operator = (const iflat_set& rhs)
+ {
+ if (&rhs != this)
+ {
+ assign(rhs.cbegin(), rhs.cend());
+ }
+
+ return *this;
+ }
+
+ protected:
+
+ //*********************************************************************
+ /// Constructor.
+ //*********************************************************************
+ iflat_set(buffer_t& buffer)
+ : flat_set_base(buffer),
+ buffer(buffer)
+ {
+ }
+
+ private:
+
+ // Disable copy construction.
+ iflat_set(const iflat_set&);
+
+ buffer_t& buffer;
+ };
+
+ //***************************************************************************
+ /// Equal operator.
+ ///\param lhs Reference to the first flat_set.
+ ///\param rhs Reference to the second flat_set.
+ ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
+ ///\ingroup flat_set
+ //***************************************************************************
+ template <typename T, typename TKeyCompare>
+ bool operator ==(const etl::iflat_set<T, TKeyCompare>& lhs, const etl::iflat_set<T, TKeyCompare>& rhs)
+ {
+ return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin());
+ }
+
+ //***************************************************************************
+ /// Not equal operator.
+ ///\param lhs Reference to the first flat_set.
+ ///\param rhs Reference to the second flat_set.
+ ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
+ ///\ingroup flat_set
+ //***************************************************************************
+ template <typename T, typename TKeyCompare>
+ bool operator !=(const etl::iflat_set<T, TKeyCompare>& lhs, const etl::iflat_set<T, TKeyCompare>& rhs)
+ {
+ return !(lhs == rhs);
+ }
+}
+
+#undef __ETL_IN_IFLAT_SET_H__
+#endif
diff --git a/lib/etl/iforward_list.h b/lib/etl/iforward_list.h
new file mode 100644
index 0000000..b663ad8
--- /dev/null
+++ b/lib/etl/iforward_list.h
@@ -0,0 +1,1055 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_IFORWARD_LIST__
+#define __ETL_IFORWARD_LIST__
+#define __ETL_IN_IFORWARD_LIST_H__
+
+#include "platform.h"
+
+#ifdef ETL_COMPILER_MICROSOFT
+#undef min
+#endif
+
+#include <iterator>
+#include <algorithm>
+#include <functional>
+#include <stddef.h>
+
+#include "pool.h"
+#include "nullptr.h"
+#include "private/forward_list_base.h"
+#include "type_traits.h"
+#include "parameter_type.h"
+
+namespace etl
+{
+ //***************************************************************************
+ /// A templated base for all etl::forward_list types.
+ ///\ingroup forward_list
+ //***************************************************************************
+ template <typename T>
+ class iforward_list : public forward_list_base
+ {
+ public:
+
+ typedef T value_type;
+ typedef T* pointer;
+ typedef const T* const_pointer;
+ typedef T& reference;
+ typedef const T& const_reference;
+ typedef size_t size_type;
+
+ protected:
+
+ typedef typename parameter_type<T, is_fundamental<T>::value || is_pointer<T>::value>::type parameter_t;
+
+ //*************************************************************************
+ /// The data node element in the forward_list.
+ //*************************************************************************
+ struct Data_Node : public Node
+ {
+ explicit Data_Node(parameter_t value)
+ : value(value)
+ {}
+
+ T value;
+ };
+
+ public:
+
+ //*************************************************************************
+ /// iterator.
+ //*************************************************************************
+ class iterator : public std::iterator<std::forward_iterator_tag, T>
+ {
+ public:
+
+ friend class iforward_list;
+
+ iterator()
+ : p_node(nullptr)
+ {
+ }
+
+ iterator(Node& node)
+ : p_node(&node)
+ {
+ }
+
+ iterator(const iterator& other)
+ : p_node(other.p_node)
+ {
+ }
+
+ iterator& operator ++()
+ {
+ p_node = p_node->next;
+ return *this;
+ }
+
+ iterator operator ++(int)
+ {
+ iterator temp(*this);
+ p_node = p_node->next;
+ return temp;
+ }
+
+ iterator operator =(const iterator& other)
+ {
+ p_node = other.p_node;
+ return *this;
+ }
+
+ reference operator *()
+ {
+ return iforward_list::data_cast(p_node)->value;
+ }
+
+ const_reference operator *() const
+ {
+ return iforward_list::data_cast(p_node)->value;
+ }
+
+ pointer operator &()
+ {
+ return &(iforward_list::data_cast(p_node)->value);
+ }
+
+ const_pointer operator &() const
+ {
+ return &(iforward_list::data_cast(p_node)->value);
+ }
+
+ pointer operator ->()
+ {
+ return &(iforward_list::data_cast(p_node)->value);
+ }
+
+ const_pointer operator ->() const
+ {
+ return &(iforward_list::data_cast(p_node)->value);
+ }
+
+ friend bool operator == (const iterator& lhs, const iterator& rhs)
+ {
+ return lhs.p_node == rhs.p_node;
+ }
+
+ friend bool operator != (const iterator& lhs, const iterator& rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+ private:
+
+ Node* p_node;
+ };
+
+ //*************************************************************************
+ /// const_iterator
+ //*************************************************************************
+ class const_iterator : public std::iterator<std::forward_iterator_tag, const T>
+ {
+ public:
+
+ friend class iforward_list;
+
+ const_iterator()
+ : p_node(nullptr)
+ {
+ }
+
+ const_iterator(Node& node)
+ : p_node(&node)
+ {
+ }
+
+ const_iterator(const Node& node)
+ : p_node(&node)
+ {
+ }
+
+ const_iterator(const typename iforward_list::iterator& other)
+ : p_node(other.p_node)
+ {
+ }
+
+ const_iterator(const const_iterator& other)
+ : p_node(other.p_node)
+ {
+ }
+
+ const_iterator& operator ++()
+ {
+ p_node = p_node->next;
+ return *this;
+ }
+
+ const_iterator operator ++(int)
+ {
+ const_iterator temp(*this);
+ p_node = p_node->next;
+ return temp;
+ }
+
+ const_iterator operator =(const const_iterator& other)
+ {
+ p_node = other.p_node;
+ return *this;
+ }
+
+ const_reference operator *() const
+ {
+ return iforward_list::data_cast(p_node)->value;
+ }
+
+ const_pointer operator &() const
+ {
+ return iforward_list::data_cast(p_node)->value;
+ }
+
+ const_pointer operator ->() const
+ {
+ return &(iforward_list::data_cast(p_node)->value);
+ }
+
+ friend bool operator == (const const_iterator& lhs, const const_iterator& rhs)
+ {
+ return lhs.p_node == rhs.p_node;
+ }
+
+ friend bool operator != (const const_iterator& lhs, const const_iterator& rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+ private:
+
+ const Node* p_node;
+ };
+
+ typedef typename std::iterator_traits<iterator>::difference_type difference_type;
+
+ //*************************************************************************
+ /// Gets the beginning of the forward_list.
+ //*************************************************************************
+ iterator begin()
+ {
+ return iterator(data_cast(get_head()));
+ }
+
+ //*************************************************************************
+ /// Gets the beginning of the forward_list.
+ //*************************************************************************
+ const_iterator begin() const
+ {
+ return const_iterator(data_cast(get_head()));
+ }
+
+ //*************************************************************************
+ /// Gets before the beginning of the forward_list.
+ //*************************************************************************
+ iterator before_begin()
+ {
+ return iterator(static_cast<Data_Node&>(start_node));
+ }
+
+ //*************************************************************************
+ /// Gets before the beginning of the forward_list.
+ //*************************************************************************
+ const_iterator before_begin() const
+ {
+ return const_iterator(static_cast<const Data_Node&>(start_node));
+ }
+
+ //*************************************************************************
+ /// Gets the beginning of the forward_list.
+ //*************************************************************************
+ const_iterator cbegin() const
+ {
+ return const_iterator(get_head());
+ }
+
+ //*************************************************************************
+ /// Gets the end of the forward_list.
+ //*************************************************************************
+ iterator end()
+ {
+ return iterator();
+ }
+
+ //*************************************************************************
+ /// Gets the end of the forward_list.
+ //*************************************************************************
+ const_iterator end() const
+ {
+ return const_iterator();
+ }
+
+ //*************************************************************************
+ /// Gets the end of the forward_list.
+ //*************************************************************************
+ const_iterator cend() const
+ {
+ return const_iterator();
+ }
+
+ //*************************************************************************
+ /// Clears the forward_list.
+ //*************************************************************************
+ void clear()
+ {
+ initialise();
+ }
+
+ //*************************************************************************
+ /// Gets a reference to the first element.
+ //*************************************************************************
+ reference front()
+ {
+ return data_cast(get_head()).value;
+ }
+
+ //*************************************************************************
+ /// Gets a const reference to the first element.
+ //*************************************************************************
+ const_reference front() const
+ {
+ return data_cast(get_head()).value;
+ }
+
+ //*************************************************************************
+ /// Assigns a range of values to the forward_list.
+ /// If asserts or exceptions are enabled throws etl::forward_list_full if the forward_list does not have enough free space.
+ /// If ETL_THROW_EXCEPTIONS & _DEBUG are defined throws forward_list_iterator if the iterators are reversed.
+ //*************************************************************************
+ template <typename TIterator>
+ void assign(TIterator first, TIterator last)
+ {
+#ifdef _DEBUG
+ difference_type count = std::distance(first, last);
+ ETL_ASSERT(count >= 0, ETL_ERROR(forward_list_iterator));
+#endif
+
+ initialise();
+
+ Node* p_last_node = &start_node;
+
+ // Add all of the elements.
+ while (first != last)
+ {
+ ETL_ASSERT(!full(), ETL_ERROR(forward_list_iterator));
+
+ Data_Node& data_node = allocate_data_node(*first++);
+ join(p_last_node, &data_node);
+ data_node.next = nullptr;
+ p_last_node = &data_node;
+ ++current_size;
+ }
+ }
+
+ //*************************************************************************
+ /// Assigns 'n' copies of a value to the forward_list.
+ //*************************************************************************
+ void assign(size_t n, parameter_t value)
+ {
+ ETL_ASSERT(n <= MAX_SIZE, ETL_ERROR(forward_list_full));
+
+ initialise();
+
+ Node* p_last_node = &start_node;
+
+ // Add all of the elements.
+ while (current_size < n)
+ {
+ Data_Node& data_node = allocate_data_node(value);
+ join(p_last_node, &data_node);
+ data_node.next = nullptr;
+ p_last_node = &data_node;
+ ++current_size;
+ }
+ }
+
+ //*************************************************************************
+ /// Adds a node to the front of the forward_list so a new value can be assigned to front().
+ //*************************************************************************
+ void push_front()
+ {
+#if defined(ETL_CHECK_PUSH_POP)
+ ETL_ASSERT(!full(), ETL_ERROR(forward_list_full));
+#endif
+ Data_Node& data_node = allocate_data_node(T());
+ insert_node_after(start_node, data_node);
+ }
+
+ //*************************************************************************
+ /// Pushes a value to the front of the forward_list.
+ //*************************************************************************
+ void push_front(parameter_t value)
+ {
+#if defined(ETL_CHECK_PUSH_POP)
+ ETL_ASSERT(!full(), ETL_ERROR(forward_list_full));
+#endif
+ Data_Node& data_node = allocate_data_node(value);
+ insert_node_after(start_node, data_node);
+ }
+
+ //*************************************************************************
+ /// Removes a value from the front of the forward_list.
+ //*************************************************************************
+ void pop_front()
+ {
+#if defined(ETL_CHECK_PUSH_POP)
+ ETL_ASSERT(!empty(), ETL_ERROR(forward_list_empty));
+#endif
+ remove_node_after(start_node);
+ }
+
+ //*************************************************************************
+ /// Resizes the forward_list.
+ //*************************************************************************
+ void resize(size_t n)
+ {
+ resize(n, T());
+ }
+
+ //*************************************************************************
+ /// Resizes the forward_list.
+ /// If asserts or exceptions are enabled, will throw an etl::forward_list_full
+ /// if <b>n</b> is larger than the maximum size.
+ //*************************************************************************
+ void resize(size_t n, T value)
+ {
+ ETL_ASSERT(n <= MAX_SIZE, ETL_ERROR(forward_list_full));
+
+ size_t i = 0;
+ iterator i_node = begin();
+ iterator i_last_node;
+
+ // Find where we're currently at.
+ while ((i < n) && (i_node != end()))
+ {
+ ++i;
+ i_last_node = i_node;
+ ++i_node;
+ }
+
+ if (i_node != end())
+ {
+ // Reduce.
+ erase_after(i_last_node, end());
+ }
+ else if (i_node == end())
+ {
+ // Increase.
+ while (i < n)
+ {
+ i_last_node = insert_after(i_last_node, value);
+ ++i;
+ }
+ }
+ }
+
+ //*************************************************************************
+ /// Inserts a value to the forward_list after the specified position.
+ //*************************************************************************
+ iterator insert_after(iterator position, parameter_t value)
+ {
+ ETL_ASSERT(!full(), ETL_ERROR(forward_list_full));
+
+ Data_Node& data_node = allocate_data_node(value);
+ insert_node_after(*position.p_node, data_node);
+
+ return iterator(data_node);
+ }
+
+ //*************************************************************************
+ /// Inserts 'n' copies of a value to the forward_list after the specified position.
+ //*************************************************************************
+ void insert_after(iterator position, size_t n, parameter_t value)
+ {
+ ETL_ASSERT(!full(), ETL_ERROR(forward_list_full));
+
+ for (size_t i = 0; !full() && (i < n); ++i)
+ {
+ // Set up the next free node.
+ Data_Node& data_node = allocate_data_node(value);
+ insert_node_after(*position.p_node, data_node);
+ }
+ }
+
+ //*************************************************************************
+ /// Inserts a range of values to the forward_list after the specified position.
+ //*************************************************************************
+ template <typename TIterator>
+ void insert_after(iterator position, TIterator first, TIterator last)
+ {
+#ifdef _DEBUG
+ difference_type count = std::distance(first, last);
+ ETL_ASSERT((count + current_size) <= MAX_SIZE, ETL_ERROR(forward_list_full));
+#endif
+
+ while (first != last)
+ {
+ // Set up the next free node.
+ Data_Node& data_node = allocate_data_node(*first++);
+ insert_node_after(*position.p_node, data_node);
+ ++position;
+ }
+ }
+
+ //*************************************************************************
+ /// Erases the value at the specified position.
+ //*************************************************************************
+ iterator erase_after(iterator position)
+ {
+ iterator next(position);
+ ++next;
+ ++next;
+
+ remove_node_after(*position.p_node);
+
+ return next;
+ }
+
+ //*************************************************************************
+ /// Erases a range of elements.
+ //*************************************************************************
+ iterator erase_after(iterator first, iterator last)
+ {
+ Node* p_first = first.p_node;
+ Node* p_last = last.p_node;
+ Node* p_next = p_first->next;
+
+ // Join the ends.
+ join(p_first, p_last);
+
+ p_first = p_next;
+
+ // Erase the ones in between.
+ while (p_first != p_last)
+ {
+ // One less.
+ --current_size;
+
+ p_next = p_first->next; // Remember the next node.
+ destroy_data_node(static_cast<Data_Node&>(*p_first)); // Destroy the pool object.
+ p_first = p_next; // Move to the next node.
+ }
+
+ if (p_next == nullptr)
+ {
+ return end();
+ }
+ else
+ {
+ return iterator(*p_last);
+ }
+ }
+
+ //*************************************************************************
+ /// Erases the value at the specified position.
+ //*************************************************************************
+ void move_after(const_iterator from_before, const_iterator to_before)
+ {
+ if (from_before == to_before) // Can't more to after yourself!
+ {
+ return;
+ }
+
+ Node* p_from_before = const_cast<Node*>(from_before.p_node); // We're not changing the value, just it's position.
+ Node* p_to_before = const_cast<Node*>(to_before.p_node); // We're not changing the value, just it's position.
+
+ Node* p_from = p_from_before->next;
+
+ // Disconnect from the list.
+ join(p_from_before, p_from->next);
+
+ // Attach it to the new position.
+ join(p_from, p_to_before->next);
+ join(p_to_before, p_from);
+ }
+
+ //*************************************************************************
+ /// Moves a range from one position to another within the list.
+ /// Moves a range at position 'first_before'/'last' to the position before 'to_before'.
+ //*************************************************************************
+ void move_after(const_iterator first_before, const_iterator last, const_iterator to_before)
+ {
+ if ((first_before == to_before) || (last == to_before))
+ {
+ return; // Can't more to before yourself!
+ }
+
+#ifdef _DEBUG
+ // Check that we are not doing an illegal move!
+ for (const_iterator item = first_before; item != last; ++item)
+ {
+ ETL_ASSERT(item != to_before, ETL_ERROR(forward_list_iterator));
+ }
+#endif
+
+ Node* p_first_before = const_cast<Node*>(first_before.p_node); // We're not changing the value, just it's position.
+ Node* p_last = const_cast<Node*>(last.p_node); // We're not changing the value, just it's position.
+ Node* p_to_before = const_cast<Node*>(to_before.p_node); // We're not changing the value, just it's position.
+ Node* p_first = p_first_before->next;
+ Node* p_final = p_first_before;
+
+ // Find the last node that will be moved.
+ while (p_final->next != p_last)
+ {
+ p_final = p_final->next;
+ }
+
+ // Disconnect from the list.
+ join(p_first_before, p_final->next);
+
+ // Attach it to the new position.
+ join(p_final, p_to_before->next);
+ join(p_to_before, p_first);
+ }
+
+ //*************************************************************************
+ /// Removes all but the first element from every consecutive group of equal
+ /// elements in the container.
+ //*************************************************************************
+ void unique()
+ {
+ unique(std::equal_to<T>());
+ }
+
+ //*************************************************************************
+ /// Removes all but the one element from every consecutive group of equal
+ /// elements in the container.
+ //*************************************************************************
+ template <typename TIsEqual>
+ void unique(TIsEqual isEqual)
+ {
+ if (empty())
+ {
+ return;
+ }
+
+ Node* last = &get_head();
+ Node* current = last->next;
+
+ while (current != nullptr)
+ {
+ // Is this value the same as the last?
+ if (isEqual(data_cast(current)->value, data_cast(last)->value))
+ {
+ remove_node_after(*last);
+ }
+ else
+ {
+ // Move on one.
+ last = current;
+ }
+
+ current = last->next;
+ }
+ }
+
+ //*************************************************************************
+ /// Sort using in-place merge sort algorithm.
+ /// Uses 'less-than operator as the predicate.
+ //*************************************************************************
+ void sort()
+ {
+ sort(std::less<T>());
+ }
+
+ //*************************************************************************
+ /// Sort using in-place merge sort algorithm.
+ /// Uses a supplied predicate function or functor.
+ /// This is not my algorithm. I got it off the web somewhere.
+ //*************************************************************************
+ template <typename TCompare>
+ void sort(TCompare compare)
+ {
+ iterator p_left;
+ iterator p_right;
+ iterator p_node;
+ iterator p_head;
+ iterator p_tail;
+ int list_size = 1;
+ int number_of_merges;
+ int left_size;
+ int right_size;
+
+ if (is_trivial_list())
+ {
+ return;
+ }
+
+ while (true)
+ {
+ p_left = begin();
+ p_head = before_begin();
+ p_tail = before_begin();
+
+ number_of_merges = 0; // Count the number of merges we do in this pass.
+
+ while (p_left != end())
+ {
+ ++number_of_merges; // There exists a merge to be done.
+ p_right = p_left;
+ left_size = 0;
+
+ // Step 'list_size' places along from left
+ for (int i = 0; i < list_size; ++i)
+ {
+ ++left_size;
+
+ ++p_right;
+
+ if (p_right == end())
+ {
+ break;
+ }
+ }
+
+ // If right hasn't fallen off end, we have two lists to merge.
+ right_size = list_size;
+
+ // Now we have two lists. Merge them.
+ while (left_size > 0 || (right_size > 0 && p_right != end()))
+ {
+ // Decide whether the next node of merge comes from left or right.
+ if (left_size == 0)
+ {
+ // Left is empty. The node must come from right.
+ p_node = p_right;
+ ++p_right;
+ --right_size;
+ }
+ else if (right_size == 0 || p_right == end())
+ {
+ // Right is empty. The node must come from left.
+ p_node = p_left;
+ ++p_left;
+ --left_size;
+ }
+ else if (compare(*p_left, *p_right))
+ {
+ // First node of left is lower or same. The node must come from left.
+ p_node = p_left;
+ ++p_left;
+ --left_size;
+ }
+ else
+ {
+ // First node of right is lower. The node must come from right.
+ p_node = p_right;
+ ++p_right;
+ --right_size;
+ }
+
+ // Add the next node to the merged head.
+ if (p_head == before_begin())
+ {
+ join(p_head.p_node, p_node.p_node);
+ p_head = p_node;
+ p_tail = p_node;
+ }
+ else
+ {
+ join(p_tail.p_node, p_node.p_node);
+ p_tail = p_node;
+ }
+
+ p_tail.p_node->next = nullptr;
+ }
+
+ // Now left has stepped `list_size' places along, and right has too.
+ p_left = p_right;
+ }
+
+ // If we have done only one merge, we're finished.
+ if (number_of_merges <= 1) // Allow for number_of_merges == 0, the empty head case
+ {
+ return;
+ }
+
+ // Otherwise repeat, merging lists twice the size
+ list_size *= 2;
+ }
+ }
+
+ //*************************************************************************
+ // Removes the values specified.
+ //*************************************************************************
+ void remove(parameter_t value)
+ {
+ iterator i_item = begin();
+ iterator i_last_item = before_begin();
+
+ while (i_item != end())
+ {
+ if (*i_item == value)
+ {
+ i_item = erase_after(i_last_item);
+ }
+ else
+ {
+ ++i_item;
+ ++i_last_item;
+ }
+ }
+ }
+
+ //*************************************************************************
+ /// Removes according to a predicate.
+ //*************************************************************************
+ template <typename TPredicate>
+ void remove_if(TPredicate predicate)
+ {
+ iterator i_item = begin();
+ iterator i_last_item = before_begin();
+
+ while (i_item != end())
+ {
+ if (predicate(*i_item))
+ {
+ i_item = erase_after(i_last_item);
+ }
+ else
+ {
+ ++i_item;
+ ++i_last_item;
+ }
+ }
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ iforward_list& operator = (const iforward_list& rhs)
+ {
+ if (&rhs != this)
+ {
+ assign(rhs.cbegin(), rhs.cend());
+ }
+
+ return *this;
+ }
+
+ protected:
+
+ //*************************************************************************
+ /// Constructor.
+ //*************************************************************************
+ iforward_list(etl::ipool<Data_Node>& node_pool, size_t max_size_)
+ : forward_list_base(max_size_),
+ p_node_pool(&node_pool)
+ {
+ }
+
+ //*************************************************************************
+ /// Initialise the forward_list.
+ //*************************************************************************
+ void initialise()
+ {
+ if (!empty())
+ {
+ p_node_pool->release_all();
+ }
+
+ current_size = 0;
+ start_node.next = nullptr;
+ }
+
+ private:
+
+ /// The pool of data nodes used in the list.
+ etl::ipool<Data_Node>* p_node_pool;
+
+ //*************************************************************************
+ /// Downcast a Node* to a Data_Node*
+ //*************************************************************************
+ static Data_Node* data_cast(Node* p_node)
+ {
+ return static_cast<Data_Node*>(p_node);
+ }
+
+ //*************************************************************************
+ /// Downcast a Node& to a Data_Node&
+ //*************************************************************************
+ static Data_Node& data_cast(Node& node)
+ {
+ return static_cast<Data_Node&>(node);
+ }
+
+ //*************************************************************************
+ /// Downcast a const Node* to a const Data_Node*
+ //*************************************************************************
+ static const Data_Node* data_cast(const Node* p_node)
+ {
+ return static_cast<const Data_Node*>(p_node);
+ }
+
+ //*************************************************************************
+ /// Downcast a const Node& to a const Data_Node&
+ //*************************************************************************
+ static const Data_Node& data_cast(const Node& node)
+ {
+ return static_cast<const Data_Node&>(node);
+ }
+
+ //*************************************************************************
+ /// Remove a node.
+ //*************************************************************************
+ void remove_node_after(Node& node)
+ {
+ // The node to erase.
+ Node* p_node = node.next;
+
+ if (p_node != nullptr)
+ {
+ // Disconnect the node from the forward_list.
+ join(&node, p_node->next);
+
+ // Destroy the pool object.
+ destroy_data_node(static_cast<Data_Node&>(*p_node));
+
+ // One less.
+ --current_size;
+ }
+ }
+
+ //*************************************************************************
+ /// Allocate a Data_Node.
+ //*************************************************************************
+ Data_Node& allocate_data_node(parameter_t value) const
+ {
+ return *(p_node_pool->allocate(Data_Node(value)));
+ }
+
+ //*************************************************************************
+ /// Destroy a Data_Node.
+ //*************************************************************************
+ void destroy_data_node(Data_Node& node) const
+ {
+ p_node_pool->release(node);
+ }
+
+ // Disable copy construction.
+ iforward_list(const iforward_list&);
+ };
+}
+
+//*************************************************************************
+/// Equal operator.
+///\param lhs Reference to the first forward_list.
+///\param rhs Reference to the second forward_list.
+///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>.
+//*************************************************************************
+template <typename T>
+bool operator ==(const etl::iforward_list<T>& lhs, const etl::iforward_list<T>& rhs)
+{
+ return (lhs.size() == rhs.size()) &&
+ std::equal(lhs.begin(), lhs.end(), rhs.begin());
+}
+
+//*************************************************************************
+/// Not equal operator.
+///\param lhs Reference to the first forward_list.
+///\param rhs Reference to the second forward_list.
+///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>.
+//*************************************************************************
+template <typename T>
+bool operator !=(const etl::iforward_list<T>& lhs, const etl::iforward_list<T>& rhs)
+{
+ return !(lhs == rhs);
+}
+
+//*************************************************************************
+/// Less than operator.
+///\param lhs Reference to the first forward_list.
+///\param rhs Reference to the second forward_list.
+///\return <b>true</b> if the first forward_list is lexicographically less than the
+/// second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename T>
+bool operator <(const etl::iforward_list<T>& lhs, const etl::iforward_list<T>& rhs)
+{
+ return std::lexicographical_compare(lhs.begin(),
+ lhs.end(),
+ rhs.begin(),
+ rhs.end());
+}
+
+//*************************************************************************
+/// Greater than operator.
+///\param lhs Reference to the first forward_list.
+///\param rhs Reference to the second forward_list.
+///\return <b>true</b> if the first forward_list is lexicographically greater than the
+/// second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename T>
+bool operator >(const etl::iforward_list<T>& lhs, const etl::iforward_list<T>& rhs)
+{
+ return (rhs < lhs);
+}
+
+//*************************************************************************
+/// Less than or equal operator.
+///\param lhs Reference to the first forward_list.
+///\param rhs Reference to the second forward_list.
+///\return <b>true</b> if the first forward_list is lexicographically less than or equal
+/// to the second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename T>
+bool operator <=(const etl::iforward_list<T>& lhs, const etl::iforward_list<T>& rhs)
+{
+ return !(lhs > rhs);
+}
+
+//*************************************************************************
+/// Greater than or equal operator.
+///\param lhs Reference to the first forward_list.
+///\param rhs Reference to the second forward_list.
+///\return <b>true</b> if the first forward_list is lexicographically greater than or
+/// equal to the second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename T>
+bool operator >=(const etl::iforward_list<T>& lhs, const etl::iforward_list<T>& rhs)
+{
+ return !(lhs < rhs);
+}
+
+#ifdef ETL_COMPILER_MICROSOFT
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#undef __ETL_IN_IFORWARD_LIST_H__
+
+#endif
diff --git a/lib/etl/ihash.h b/lib/etl/ihash.h
new file mode 100644
index 0000000..4450e9c
--- /dev/null
+++ b/lib/etl/ihash.h
@@ -0,0 +1,80 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2015 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_IHASH__
+#define __ETL_IHASH__
+
+#include <stdint.h>
+#include <utility>
+
+#include "exception.h"
+#include "error_handler.h"
+
+///\defgroup ihash Common data for all hash type classes.
+///\ingroup hash
+
+#undef ETL_FILE
+#define ETL_FILE "19"
+
+namespace etl
+{
+ //***************************************************************************
+ ///\ingroup hash
+ /// Exception base for hashes.
+ //***************************************************************************
+ class hash_exception : public exception
+ {
+ public:
+
+ hash_exception(string_type what, string_type file_name, numeric_type line_number)
+ : exception(what, file_name, line_number)
+ {}
+ };
+
+ //***************************************************************************
+ ///\ingroup vector
+ /// Hash finalised exception.
+ //***************************************************************************
+ class hash_finalised : public hash_exception
+ {
+ public:
+
+ hash_finalised(string_type file_name, numeric_type line_number)
+ : hash_exception(ETL_ERROR_TEXT("ihash:finalised", ETL_FILE"A"), file_name, line_number)
+ {}
+ };
+
+ /// For the Americans
+ typedef hash_finalised hash_finalized;
+}
+
+#undef ETL_FILE
+
+#endif
diff --git a/lib/etl/ilist.h b/lib/etl/ilist.h
new file mode 100644
index 0000000..50795bf
--- /dev/null
+++ b/lib/etl/ilist.h
@@ -0,0 +1,1207 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_ILIST__
+#define __ETL_ILIST__
+#define __ETL_IN_ILIST_H__
+
+#include <iterator>
+#include <algorithm>
+#include <functional>
+#include <stddef.h>
+
+#include "nullptr.h"
+#include "private/list_base.h"
+#include "type_traits.h"
+#include "parameter_type.h"
+#include "pool.h"
+#include "platform.h"
+
+#ifdef ETL_COMPILER_MICROSOFT
+#undef min
+#endif
+
+namespace etl
+{
+ //***************************************************************************
+ /// A templated base for all etl::list types.
+ ///\ingroup list
+ //***************************************************************************
+ template <typename T>
+ class ilist : public list_base
+ {
+ public:
+
+ typedef T value_type;
+ typedef T* pointer;
+ typedef const T* const_pointer;
+ typedef T& reference;
+ typedef const T& const_reference;
+ typedef size_t size_type;
+
+ protected:
+
+ typedef typename parameter_type<T, is_fundamental<T>::value || is_pointer<T>::value>::type parameter_t;
+
+ //*************************************************************************
+ /// The data node element in the list.
+ //*************************************************************************
+ struct data_node_t : public node_t
+ {
+ explicit data_node_t(parameter_t value)
+ : value(value)
+ {
+ }
+
+ T value;
+ };
+
+ private:
+
+ /// The pool of data nodes used in the list.
+ etl::ipool<data_node_t>* p_node_pool;
+
+ //*************************************************************************
+ /// Downcast a node_t* to a data_node_t*
+ //*************************************************************************
+ static data_node_t* data_cast(node_t* p_node)
+ {
+ return static_cast<data_node_t*>(p_node);
+ }
+
+ //*************************************************************************
+ /// Downcast a node_t& to a data_node_t&
+ //*************************************************************************
+ static data_node_t& data_cast(node_t& node)
+ {
+ return static_cast<data_node_t&>(node);
+ }
+
+ //*************************************************************************
+ /// Downcast a const node_t* to a const data_node_t*
+ //*************************************************************************
+ static const data_node_t* data_cast(const node_t* p_node)
+ {
+ return static_cast<const data_node_t*>(p_node);
+ }
+
+ //*************************************************************************
+ /// Downcast a const node_t& to a const data_node_t&
+ //*************************************************************************
+ static const data_node_t& data_cast(const node_t& node)
+ {
+ return static_cast<const data_node_t&>(node);
+ }
+
+ public:
+
+ //*************************************************************************
+ /// iterator.
+ //*************************************************************************
+ class iterator : public std::iterator<std::bidirectional_iterator_tag, T>
+ {
+ public:
+
+ friend class ilist;
+
+ iterator()
+ : p_node(nullptr)
+ {
+ }
+
+ iterator(node_t& node)
+ : p_node(&node)
+ {
+ }
+
+ iterator(const iterator& other)
+ : p_node(other.p_node)
+ {
+ }
+
+ iterator& operator ++()
+ {
+ p_node = p_node->next;
+ return *this;
+ }
+
+ iterator operator ++(int)
+ {
+ iterator temp(*this);
+ p_node = p_node->next;
+ return temp;
+ }
+
+ iterator& operator --()
+ {
+ p_node = p_node->previous;
+ return *this;
+ }
+
+ iterator operator --(int)
+ {
+ iterator temp(*this);
+ p_node = p_node->previous;
+ return temp;
+ }
+
+ iterator operator =(const iterator& other)
+ {
+ p_node = other.p_node;
+ return *this;
+ }
+
+ reference operator *()
+ {
+ return ilist::data_cast(p_node)->value;
+ }
+
+ const_reference operator *() const
+ {
+ return ilist::data_cast(p_node)->value;
+ }
+
+ pointer operator &()
+ {
+ return &(ilist::data_cast(p_node)->value);
+ }
+
+ const_pointer operator &() const
+ {
+ return &(ilist::data_cast(p_node)->value);
+ }
+
+ pointer operator ->()
+ {
+ return &(ilist::data_cast(p_node)->value);
+ }
+
+ const_pointer operator ->() const
+ {
+ return &(ilist::data_cast(p_node)->value);
+ }
+
+ friend bool operator == (const iterator& lhs, const iterator& rhs)
+ {
+ return lhs.p_node == rhs.p_node;
+ }
+
+ friend bool operator != (const iterator& lhs, const iterator& rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+ private:
+
+ node_t* p_node;
+ };
+
+ //*************************************************************************
+ /// const_iterator
+ //*************************************************************************
+ class const_iterator : public std::iterator<std::bidirectional_iterator_tag, const T>
+ {
+ public:
+
+ friend class ilist;
+
+ const_iterator()
+ : p_node(nullptr)
+ {
+ }
+
+ const_iterator(node_t& node)
+ : p_node(&node)
+ {
+ }
+
+ const_iterator(const node_t& node)
+ : p_node(&node)
+ {
+ }
+
+ const_iterator(const typename ilist::iterator& other)
+ : p_node(other.p_node)
+ {
+ }
+
+ const_iterator(const const_iterator& other)
+ : p_node(other.p_node)
+ {
+ }
+
+ const_iterator& operator ++()
+ {
+ p_node = p_node->next;
+ return *this;
+ }
+
+ const_iterator operator ++(int)
+ {
+ const_iterator temp(*this);
+ p_node = p_node->next;
+ return temp;
+ }
+
+ const_iterator& operator --()
+ {
+ p_node = p_node->previous;
+ return *this;
+ }
+
+ const_iterator operator --(int)
+ {
+ const_iterator temp(*this);
+ p_node = p_node->previous;
+ return temp;
+ }
+
+ const_iterator operator =(const const_iterator& other)
+ {
+ p_node = other.p_node;
+ return *this;
+ }
+
+ const_reference operator *() const
+ {
+ return ilist::data_cast(p_node)->value;
+ }
+
+ const_pointer operator &() const
+ {
+ return ilist::data_cast(p_node)->value;
+ }
+
+ const data_node_t* operator ->() const
+ {
+ return p_node;
+ }
+
+ friend bool operator == (const const_iterator& lhs, const const_iterator& rhs)
+ {
+ return lhs.p_node == rhs.p_node;
+ }
+
+ friend bool operator != (const const_iterator& lhs, const const_iterator& rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+ private:
+
+ const node_t* p_node;
+ };
+
+ typedef typename std::iterator_traits<iterator>::difference_type difference_type;
+
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+
+ //*************************************************************************
+ /// Gets the beginning of the list.
+ //*************************************************************************
+ iterator begin()
+ {
+ return iterator(get_head());
+ }
+
+ //*************************************************************************
+ /// Gets the beginning of the list.
+ //*************************************************************************
+ const_iterator begin() const
+ {
+ return const_iterator(get_head());
+ }
+
+ //*************************************************************************
+ /// Gets the end of the list.
+ //*************************************************************************
+ iterator end()
+ {
+ return iterator(terminal_node);
+ }
+
+ //*************************************************************************
+ /// Gets the end of the list.
+ //*************************************************************************
+ const_iterator end() const
+ {
+ return const_iterator(static_cast<const data_node_t&>(terminal_node));
+ }
+
+ //*************************************************************************
+ /// Gets the beginning of the list.
+ //*************************************************************************
+ const_iterator cbegin() const
+ {
+ return const_iterator(get_head());
+ }
+
+ //*************************************************************************
+ /// Gets the end of the list.
+ //*************************************************************************
+ const_iterator cend() const
+ {
+ return const_iterator(static_cast<const data_node_t&>(terminal_node));
+ }
+
+ //*************************************************************************
+ /// Gets the reverse beginning of the list.
+ //*************************************************************************
+ reverse_iterator rbegin()
+ {
+ return reverse_iterator(terminal_node);
+ }
+
+ //*************************************************************************
+ /// Gets the reverse beginning of the list.
+ //*************************************************************************
+ const_reverse_iterator rbegin() const
+ {
+ return const_reverse_iterator(static_cast<const data_node_t&>(terminal_node));
+ }
+
+ //*************************************************************************
+ /// Gets the reverse end of the list.
+ //*************************************************************************
+ reverse_iterator rend()
+ {
+ return reverse_iterator(get_head());
+ }
+
+ //*************************************************************************
+ /// Gets the reverse beginning of the list.
+ //*************************************************************************
+ const_reverse_iterator crbegin() const
+ {
+ return const_reverse_iterator(static_cast<const data_node_t&>(terminal_node));
+ }
+
+ //*************************************************************************
+ /// Gets the reverse end of the list.
+ //*************************************************************************
+ const_reverse_iterator crend() const
+ {
+ return const_reverse_iterator(get_head());
+ }
+
+ //*************************************************************************
+ /// Gets a reference to the first element.
+ //*************************************************************************
+ reference front()
+ {
+ return data_cast(get_head()).value;
+ }
+
+ //*************************************************************************
+ /// Gets a const reference to the first element.
+ //*************************************************************************
+ const_reference front() const
+ {
+ return data_cast(get_head()).value;
+ }
+
+ //*************************************************************************
+ /// Gets a reference to the last element.
+ //*************************************************************************
+ reference back()
+ {
+ return data_cast(get_tail()).value;
+ }
+
+ //*************************************************************************
+ /// Gets a reference to the last element.
+ //*************************************************************************
+ const_reference back() const
+ {
+ return data_cast(get_tail()).value;
+ }
+
+ //*************************************************************************
+ /// Assigns a range of values to the list.
+ /// If asserts or exceptions are enabled throws etl::list_full if the list does not have enough free space.
+ /// If ETL_THROW_EXCEPTIONS & _DEBUG are defined throws list_iterator if the iterators are reversed.
+ //*************************************************************************
+ template <typename TIterator>
+ void assign(TIterator first, TIterator last)
+ {
+#ifdef _DEBUG
+ difference_type count = std::distance(first, last);
+ ETL_ASSERT(count >= 0, ETL_ERROR(list_iterator));
+ ETL_ASSERT(size_t(count) <= MAX_SIZE, ETL_ERROR(list_full));
+#endif
+ initialise();
+
+ // Add all of the elements.
+ while (first != last)
+ {
+ data_node_t& data_node = allocate_data_node(*first);
+ join(get_tail(), data_node);
+ join(data_node, terminal_node);
+ ++first;
+ ++current_size;
+ }
+ }
+
+ //*************************************************************************
+ /// Assigns 'n' copies of a value to the list.
+ //*************************************************************************
+ void assign(size_t n, parameter_t value)
+ {
+#ifdef _DEBUG
+ ETL_ASSERT(n <= MAX_SIZE, ETL_ERROR(list_full));
+#endif
+
+ initialise();
+
+ // Add all of the elements.
+ while (current_size < n)
+ {
+ data_node_t& data_node = allocate_data_node(value);
+ join(*terminal_node.previous, data_node);
+ join(data_node, terminal_node);
+ ++current_size;
+ }
+ }
+
+ //*************************************************************************
+ /// Adds a node to the front of the list so a new value can be assigned to front().
+ //*************************************************************************
+ void push_front()
+ {
+#if defined(ETL_CHECK_PUSH_POP)
+ ETL_ASSERT(!full(), ETL_ERROR(list_full));
+#endif
+ data_node_t& data_node = allocate_data_node(T());
+ insert_node(get_head(), data_node);
+ }
+
+ //*************************************************************************
+ /// Pushes a value to the front of the list.
+ //*************************************************************************
+ void push_front(parameter_t value)
+ {
+#if defined(ETL_CHECK_PUSH_POP)
+ ETL_ASSERT(!full(), ETL_ERROR(list_full));
+#endif
+ node_t& data_node = allocate_data_node(value);
+ insert_node(get_head(), data_node);
+ }
+
+ //*************************************************************************
+ /// Removes a value from the front of the list.
+ //*************************************************************************
+ void pop_front()
+ {
+#if defined(ETL_CHECK_PUSH_POP)
+ ETL_ASSERT(!empty(), ETL_ERROR(list_empty));
+#endif
+ node_t& node = get_head();
+ remove_node(node);
+ }
+
+ //*************************************************************************
+ /// Adds a node to the back of the list so a new value can be assigned to back().
+ //*************************************************************************
+ void push_back()
+ {
+#if defined(ETL_CHECK_PUSH_POP)
+ ETL_ASSERT(!full(), ETL_ERROR(list_full));
+#endif
+ data_node_t& data_node = allocate_data_node(T());
+ insert_node(terminal_node, data_node);
+ }
+
+ //*************************************************************************
+ /// Pushes a value to the back of the list..
+ //*************************************************************************
+ void push_back(parameter_t value)
+ {
+#if defined(ETL_CHECK_PUSH_POP)
+ ETL_ASSERT(!full(), ETL_ERROR(list_full));
+#endif
+ data_node_t& data_node = allocate_data_node(value);
+ insert_node(terminal_node, data_node);
+ }
+
+ //*************************************************************************
+ /// Removes a value from the back of the list.
+ //*************************************************************************
+ void pop_back()
+ {
+#if defined(ETL_CHECK_PUSH_POP)
+ ETL_ASSERT(!empty(), ETL_ERROR(list_empty));
+#endif
+ node_t& node = get_tail();
+ remove_node(node);
+ }
+
+ //*************************************************************************
+ /// Inserts a value to the list at the specified position.
+ //*************************************************************************
+ iterator insert(iterator position, const value_type& value)
+ {
+ ETL_ASSERT(!full(), ETL_ERROR(list_full));
+
+ data_node_t& data_node = allocate_data_node(value);
+ insert_node(*position.p_node, data_node);
+
+ return iterator(data_node);
+ }
+
+ //*************************************************************************
+ /// Inserts 'n' copies of a value to the list at the specified position.
+ //*************************************************************************
+ void insert(iterator position, size_t n, const value_type& value)
+ {
+ for (size_t i = 0; i < n; ++i)
+ {
+ ETL_ASSERT(!full(), ETL_ERROR(list_full));
+
+ // Set up the next free node and insert.
+ data_node_t& data_node = allocate_data_node(value);
+ insert_node(*position.p_node, data_node);
+ }
+ }
+
+ //*************************************************************************
+ /// Inserts a range of values to the list at the specified position.
+ //*************************************************************************
+ template <typename TIterator>
+ void insert(iterator position, TIterator first, TIterator last)
+ {
+ while (first != last)
+ {
+ ETL_ASSERT(!full(), ETL_ERROR(list_full));
+
+ // Set up the next free node and insert.
+ data_node_t& data_node = allocate_data_node(*first++);
+ insert_node(*position.p_node, data_node);
+ }
+ }
+
+ //*************************************************************************
+ /// Erases the value at the specified position.
+ //*************************************************************************
+ iterator erase(iterator position)
+ {
+ iterator next(position);
+ ++next;
+
+ remove_node(*position.p_node);
+
+ return next;
+ }
+
+ //*************************************************************************
+ /// Erases a range of elements.
+ //*************************************************************************
+ iterator erase(iterator first, iterator last)
+ {
+ node_t* p_first = first.p_node;
+ node_t* p_last = last.p_node;
+ node_t* p_next;
+
+ // Join the ends.
+ join(*(p_first->previous), *p_last);
+
+ // Erase the ones in between.
+ while (p_first != p_last)
+ {
+ // One less.
+ --current_size;
+
+ p_next = p_first->next; // Remember the next node.
+ destroy_data_node(static_cast<data_node_t&>(*p_first)); // Destroy the current node.
+ p_first = p_next; // Move to the next node.
+ }
+
+ return last;
+ }
+
+ //*************************************************************************
+ /// Resizes the list.
+ //*************************************************************************
+ void resize(size_t n)
+ {
+ resize(n, T());
+ }
+
+ //*************************************************************************
+ /// Resizes the list.
+ //*************************************************************************
+ void resize(size_t n, parameter_t value)
+ {
+ ETL_ASSERT(n <= MAX_SIZE, ETL_ERROR(list_full));
+
+ // Smaller?
+ if (n < size())
+ {
+ iterator i_start = end();
+ std::advance(i_start, -difference_type(size() - n));
+ erase(i_start, end());
+ }
+ // Larger?
+ else if (n > size())
+ {
+ insert(end(), n - size(), value);
+ }
+ }
+
+ //*************************************************************************
+ /// Clears the list.
+ //*************************************************************************
+ void clear()
+ {
+ initialise();
+ }
+
+ //*************************************************************************
+ // Removes the values specified.
+ //*************************************************************************
+ void remove(const value_type& value)
+ {
+ iterator iValue = begin();
+
+ while (iValue != end())
+ {
+ if (value == *iValue)
+ {
+ iValue = erase(iValue);
+ }
+ else
+ {
+ ++iValue;
+ }
+ }
+ }
+
+ //*************************************************************************
+ /// Removes according to a predicate.
+ //*************************************************************************
+ template <typename TPredicate>
+ void remove_if(TPredicate predicate)
+ {
+ iterator iValue = begin();
+
+ while (iValue != end())
+ {
+ if (predicate(*iValue))
+ {
+ iValue = erase(iValue);
+ }
+ else
+ {
+ ++iValue;
+ }
+ }
+ }
+
+ //*************************************************************************
+ /// Removes all but the first element from every consecutive group of equal
+ /// elements in the container.
+ //*************************************************************************
+ void unique()
+ {
+ unique(std::equal_to<T>());
+ }
+
+ //*************************************************************************
+ /// Removes all but the first element from every consecutive group of equal
+ /// elements in the container.
+ //*************************************************************************
+ template <typename TIsEqual>
+ void unique(TIsEqual isEqual)
+ {
+ if (empty())
+ {
+ return;
+ }
+
+ iterator i_item = begin();
+ ++i_item;
+ iterator i_previous = begin();
+
+ while (i_item != end())
+ {
+ if (isEqual(*i_previous, *i_item))
+ {
+ i_item = erase(i_item);
+ }
+ else
+ {
+ i_previous = i_item;
+ ++i_item;
+ }
+ }
+ }
+
+ //*************************************************************************
+ /// Splices from another list to this.
+ //*************************************************************************
+ void splice(iterator to, ilist& other)
+ {
+ if (&other != this)
+ {
+ insert(to, other.begin(), other.end());
+ other.erase(other.begin(), other.end());
+ }
+ }
+
+ //*************************************************************************
+ /// Splices an element from another list to this.
+ //*************************************************************************
+ void splice(iterator to, ilist& other, iterator from)
+ {
+ if (&other == this)
+ {
+ // Internal move.
+ move(to, from);
+ }
+ else
+ {
+ // From another list.
+ insert(to, *from);
+ other.erase(from);
+ }
+ }
+
+ //*************************************************************************
+ /// Splices a range of elements from another list to this.
+ //*************************************************************************
+ void splice(iterator to, ilist& other, iterator first, iterator last)
+ {
+ if (&other == this)
+ {
+ // Internal move.
+ move(to, first, last);
+ }
+ else
+ {
+ // From another list.
+ insert(to, first, last);
+ other.erase(first, last);
+ }
+ }
+
+ //*************************************************************************
+ /// Merge another list into this one. Both lists should be sorted.
+ //*************************************************************************
+ void merge(ilist& other)
+ {
+ merge(other, std::less<value_type>());
+ }
+
+ //*************************************************************************
+ /// Merge another list into this one. Both lists should be sorted.
+ //*************************************************************************
+ template <typename TCompare>
+ void merge(ilist& other, TCompare compare)
+ {
+ if (!other.empty())
+ {
+#if _DEBUG
+ ETL_ASSERT(etl::is_sorted(other.begin(), other.end(), compare), ETL_ERROR(list_unsorted));
+ ETL_ASSERT(etl::is_sorted(begin(), end(), compare), ETL_ERROR(list_unsorted));
+#endif
+
+ ilist::iterator other_begin = other.begin();
+ ilist::iterator other_end = other.end();
+
+ ilist::iterator this_begin = begin();
+ ilist::iterator this_end = end();
+
+ while ((this_begin != this_end) && (other_begin != other_end))
+ {
+ // Find the place to insert.
+ while ((this_begin != this_end) && !(compare(*other_begin, *this_begin)))
+ {
+ ++this_begin;
+ }
+
+ // Insert.
+ if (this_begin != this_end)
+ {
+ while ((other_begin != other_end) && (compare(*other_begin, *this_begin)))
+ {
+ insert(this_begin, *other_begin);
+ ++other_begin;
+ }
+ }
+ }
+
+ // Any left over?
+ if ((this_begin == this_end) && (other_begin != other_end))
+ {
+ insert(this_end, other_begin, other_end);
+ }
+
+ other.clear();
+ }
+ }
+
+ //*************************************************************************
+ /// Sort using in-place merge sort algorithm.
+ /// Uses 'less-than operator as the predicate.
+ //*************************************************************************
+ void sort()
+ {
+ sort(std::less<T>());
+ }
+
+ //*************************************************************************
+ /// Sort using in-place merge sort algorithm.
+ /// Uses a supplied predicate function or functor.
+ /// This is not my algorithm. I got it off the web somewhere.
+ //*************************************************************************
+ template <typename TCompare>
+ void sort(TCompare compare)
+ {
+ iterator i_left;
+ iterator i_right;
+ iterator i_node;
+ iterator i_head;
+ iterator i_tail;
+ int list_size = 1;
+ int number_of_merges;
+ int left_size;
+ int right_size;
+
+ if (is_trivial_list())
+ {
+ return;
+ }
+
+ while (true)
+ {
+ i_left = begin();
+ i_head = end();
+ i_tail = end();
+
+ number_of_merges = 0; // Count the number of merges we do in this pass.
+
+ while (i_left != end())
+ {
+ ++number_of_merges; // There exists a merge to be done.
+ i_right = i_left;
+ left_size = 0;
+
+ // Step 'list_size' places along from left
+ for (int i = 0; i < list_size; ++i)
+ {
+ ++left_size;
+ ++i_right;
+
+ if (i_right == end())
+ {
+ break;
+ }
+ }
+
+ // If right hasn't fallen off end, we have two lists to merge.
+ right_size = list_size;
+
+ // Now we have two lists. Merge them.
+ while (left_size > 0 || (right_size > 0 && i_right != end()))
+ {
+ // Decide whether the next node of merge comes from left or right.
+ if (left_size == 0)
+ {
+ // Left is empty. The node must come from right.
+ i_node = i_right++;
+ --right_size;
+ }
+ else if (right_size == 0 || i_right == end())
+ {
+ // Right is empty. The node must come from left.
+ i_node = i_left++;
+ --left_size;
+ }
+ else if (compare(*i_left, *i_right))
+ {
+ // First node of left is lower or same. The node must come from left.
+ i_node = i_left++;
+ --left_size;
+ }
+ else
+ {
+ // First node of right is lower. The node must come from right.
+ i_node = i_right;
+ ++i_right;
+ --right_size;
+ }
+
+ // Add the next node to the merged head.
+ if (i_head == end())
+ {
+ join(*i_head.p_node, *i_node.p_node);
+ i_head = i_node;
+ i_tail = i_node;
+ }
+ else
+ {
+ join(*i_tail.p_node, *i_node.p_node);
+ i_tail = i_node;
+ }
+
+ join(*i_tail.p_node, terminal_node);
+ }
+
+ // Now left has stepped `list_size' places along, and right has too.
+ i_left = i_right;
+ }
+
+ // If we have done only one merge, we're finished.
+ if (number_of_merges <= 1) // Allow for number_of_merges == 0, the empty head case
+ {
+ return;
+ }
+
+ // Otherwise repeat, merging lists twice the size
+ list_size *= 2;
+ }
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ ilist& operator = (const ilist& rhs)
+ {
+ if (&rhs != this)
+ {
+ assign(rhs.cbegin(), rhs.cend());
+ }
+
+ return *this;
+ }
+
+ protected:
+
+ //*************************************************************************
+ /// Constructor.
+ //*************************************************************************
+ ilist(etl::ipool<data_node_t>& node_pool, size_t max_size_)
+ : list_base(max_size_),
+ p_node_pool(&node_pool)
+ {
+ }
+
+ //*************************************************************************
+ /// Initialise the list.
+ //*************************************************************************
+ void initialise()
+ {
+ if (!empty())
+ {
+ p_node_pool->release_all();
+ }
+
+ current_size = 0;
+ join(terminal_node, terminal_node);
+ }
+
+ private:
+
+ //*************************************************************************
+ /// Moves an element from one position to another within the list.
+ /// Moves the element at position 'from' to the position before 'to'.
+ //*************************************************************************
+ void move(iterator to, iterator from)
+ {
+ if (from == to)
+ {
+ return; // Can't more to before yourself!
+ }
+
+ node_t& from_node = *from.p_node;
+ node_t& to_node = *to.p_node;
+
+ // Disconnect the node from the list.
+ join(*from_node.previous, *from_node.next);
+
+ // Attach it to the new position.
+ join(*to_node.previous, from_node);
+ join(from_node, to_node);
+ }
+
+ //*************************************************************************
+ /// Moves a range from one position to another within the list.
+ /// Moves a range at position 'first'/'last' to the position before 'to'.
+ //*************************************************************************
+ void move(iterator to, iterator first, iterator last)
+ {
+ if ((first == to) || (last == to))
+ {
+ return; // Can't more to before yourself!
+ }
+
+#ifdef _DEBUG
+ // Check that we are not doing an illegal move!
+ for (const_iterator item = first; item != last; ++item)
+ {
+ ETL_ASSERT(item != to, ETL_ERROR(list_iterator));
+ }
+#endif
+
+ node_t& first_node = *first.p_node;
+ node_t& last_node = *last.p_node;
+ node_t& to_node = *to.p_node;
+ node_t& final_node = *last_node.previous;
+
+ // Disconnect the range from the list.
+ join(*first_node.previous, last_node);
+
+ // Attach it to the new position.
+ join(*to_node.previous, first_node);
+ join(final_node, to_node);
+ }
+
+ //*************************************************************************
+ /// Remove a node.
+ //*************************************************************************
+ void remove_node(node_t& node)
+ {
+ // Disconnect the node from the list.
+ join(*node.previous, *node.next);
+
+ // Destroy the pool object.
+ destroy_data_node(static_cast<data_node_t&>(node));
+
+ // One less.
+ --current_size;
+ }
+
+ //*************************************************************************
+ /// Allocate a data_node_t.
+ //*************************************************************************
+ data_node_t& allocate_data_node(parameter_t value) const
+ {
+ return *(p_node_pool->allocate(data_node_t(value)));
+ }
+
+ //*************************************************************************
+ /// Destroy a data_node_t.
+ //*************************************************************************
+ void destroy_data_node(data_node_t& node) const
+ {
+ p_node_pool->release(&node);
+ }
+
+ // Disable copy construction.
+ ilist(const ilist&);
+ };
+}
+
+//*************************************************************************
+/// Equal operator.
+///\param lhs Reference to the first list.
+///\param rhs Reference to the second list.
+///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>.
+//*************************************************************************
+template <typename T>
+bool operator ==(const etl::ilist<T>& lhs, const etl::ilist<T>& rhs)
+{
+ return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin());
+}
+
+//*************************************************************************
+/// Not equal operator.
+///\param lhs Reference to the first list.
+///\param rhs Reference to the second list.
+///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>.
+//*************************************************************************
+template <typename T>
+bool operator !=(const etl::ilist<T>& lhs, const etl::ilist<T>& rhs)
+{
+ return !(lhs == rhs);
+}
+
+//*************************************************************************
+/// Less than operator.
+///\param lhs Reference to the first list.
+///\param rhs Reference to the second list.
+///\return <b>true</b> if the first list is lexicographically less than the
+/// second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename T>
+bool operator <(const etl::ilist<T>& lhs, const etl::ilist<T>& rhs)
+{
+ return std::lexicographical_compare(lhs.begin(),
+ lhs.end(),
+ rhs.begin(),
+ rhs.end());
+}
+
+//*************************************************************************
+/// Greater than operator.
+///\param lhs Reference to the first list.
+///\param rhs Reference to the second list.
+///\return <b>true</b> if the first list is lexicographically greater than the
+/// second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename T>
+bool operator >(const etl::ilist<T>& lhs, const etl::ilist<T>& rhs)
+{
+ return (rhs < lhs);
+}
+
+//*************************************************************************
+/// Less than or equal operator.
+///\param lhs Reference to the first list.
+///\param rhs Reference to the second list.
+///\return <b>true</b> if the first list is lexicographically less than or equal
+/// to the second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename T>
+bool operator <=(const etl::ilist<T>& lhs, const etl::ilist<T>& rhs)
+{
+ return !(lhs > rhs);
+}
+
+//*************************************************************************
+/// Greater than or equal operator.
+///\param lhs Reference to the first list.
+///\param rhs Reference to the second list.
+///\return <b>true</b> if the first list is lexicographically greater than or
+/// equal to the second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename T>
+bool operator >=(const etl::ilist<T>& lhs, const etl::ilist<T>& rhs)
+{
+ return !(lhs < rhs);
+}
+
+#ifdef ETL_COMPILER_MICROSOFT
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#undef __ETL_IN_ILIST_H__
+
+#endif
diff --git a/lib/etl/imap.h b/lib/etl/imap.h
new file mode 100644
index 0000000..ecf4ddb
--- /dev/null
+++ b/lib/etl/imap.h
@@ -0,0 +1,1691 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove, rlindeman
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_IMAP__
+#define __ETL_IMAP__
+#define __ETL_IN_IMAP_H__
+
+#include <iterator>
+#include <algorithm>
+#include <functional>
+#include <stddef.h>
+
+#include "nullptr.h"
+#include "private/map_base.h"
+#include "type_traits.h"
+#include "parameter_type.h"
+#include "pool.h"
+#include "platform.h"
+
+#ifdef ETL_COMPILER_MICROSOFT
+#undef min
+#endif
+
+namespace etl
+{
+ //***************************************************************************
+ /// A templated base for all etl::map types.
+ ///\ingroup map
+ //***************************************************************************
+ template <typename TKey, typename TMapped, typename TKeyCompare>
+ class imap : public map_base
+ {
+ public:
+
+ typedef TKey key_type;
+ typedef std::pair<const TKey, TMapped> value_type;
+ typedef TMapped mapped_type;
+ typedef TKeyCompare key_compare;
+ typedef value_type& reference;
+ typedef const value_type& const_reference;
+ typedef value_type* pointer;
+ typedef const value_type* const_pointer;
+ typedef size_t size_type;
+
+ //*************************************************************************
+ /// How to compare two key elements.
+ //*************************************************************************
+ struct key_comp
+ {
+ bool operator ()(const key_type& key1, const key_type& key2) const
+ {
+ return key_compare()(key1, key2);
+ }
+ };
+
+ //*************************************************************************
+ /// How to compare two value elements.
+ //*************************************************************************
+ struct value_comp
+ {
+ bool operator ()(const value_type& value1, const value_type& value2) const
+ {
+ return key_compare()(value1.first, value2.first);
+ }
+ };
+
+ protected:
+
+ //*************************************************************************
+ /// The data node element in the map.
+ //*************************************************************************
+ struct Data_Node : public Node
+ {
+ explicit Data_Node(value_type value)
+ : value(value)
+ {
+ }
+
+ value_type value;
+ };
+
+ /// Defines the key value parameter type
+ typedef typename parameter_type<TKey>::type key_value_parameter_t;
+
+ //*************************************************************************
+ /// How to compare node elements.
+ //*************************************************************************
+ bool node_comp(const Data_Node& node1, const Data_Node& node2) const
+ {
+ return key_compare()(node1.value.first, node2.value.first);
+ }
+ bool node_comp(const Data_Node& node, const key_value_parameter_t& key) const
+ {
+ return key_compare()(node.value.first, key);
+ }
+ bool node_comp(const key_value_parameter_t& key, const Data_Node& node) const
+ {
+ return key_compare()(key, node.value.first);
+ }
+
+ private:
+
+ /// The pool of data nodes used in the map.
+ ipool<Data_Node>* p_node_pool;
+
+ //*************************************************************************
+ /// Downcast a Node* to a Data_Node*
+ //*************************************************************************
+ static Data_Node* data_cast(Node* p_node)
+ {
+ return static_cast<Data_Node*>(p_node);
+ }
+
+ //*************************************************************************
+ /// Downcast a Node& to a Data_Node&
+ //*************************************************************************
+ static Data_Node& data_cast(Node& node)
+ {
+ return static_cast<Data_Node&>(node);
+ }
+
+ //*************************************************************************
+ /// Downcast a const Node* to a const Data_Node*
+ //*************************************************************************
+ static const Data_Node* data_cast(const Node* p_node)
+ {
+ return static_cast<const Data_Node*>(p_node);
+ }
+
+ //*************************************************************************
+ /// Downcast a const Node& to a const Data_Node&
+ //*************************************************************************
+ static const Data_Node& data_cast(const Node& node)
+ {
+ return static_cast<const Data_Node&>(node);
+ }
+
+ public:
+
+ //*************************************************************************
+ /// iterator.
+ //*************************************************************************
+ class iterator : public std::iterator<std::bidirectional_iterator_tag, value_type>
+ {
+ public:
+
+ friend class imap;
+
+ iterator()
+ : p_map(nullptr)
+ , p_node(nullptr)
+ {
+ }
+
+ iterator(imap& map)
+ : p_map(&map)
+ , p_node(nullptr)
+ {
+ }
+
+ iterator(imap& map, Node* node)
+ : p_map(&map)
+ , p_node(node)
+ {
+ }
+
+ iterator(const iterator& other)
+ : p_map(other.p_map)
+ , p_node(other.p_node)
+ {
+ }
+
+ ~iterator()
+ {
+ }
+
+ iterator& operator ++()
+ {
+ p_map->next_node(p_node);
+ return *this;
+ }
+
+ iterator operator ++(int)
+ {
+ iterator temp(*this);
+ p_map->next_node(p_node);
+ return temp;
+ }
+
+ iterator& operator --()
+ {
+ p_map->prev_node(p_node);
+ return *this;
+ }
+
+ iterator operator --(int)
+ {
+ iterator temp(*this);
+ p_map->prev_node(p_node);
+ return temp;
+ }
+
+ iterator operator =(const iterator& other)
+ {
+ p_map = other.p_map;
+ p_node = other.p_node;
+ return *this;
+ }
+
+ reference operator *()
+ {
+ return imap::data_cast(p_node)->value;
+ }
+
+ const_reference operator *() const
+ {
+ return imap::data_cast(p_node)->value;
+ }
+
+ pointer operator &()
+ {
+ return &(imap::data_cast(p_node)->value);
+ }
+
+ const_pointer operator &() const
+ {
+ return &(imap::data_cast(p_node)->value);
+ }
+
+ pointer operator ->()
+ {
+ return &(imap::data_cast(p_node)->value);
+ }
+
+ const_pointer operator ->() const
+ {
+ return &(imap::data_cast(p_node)->value);
+ }
+
+ friend bool operator == (const iterator& lhs, const iterator& rhs)
+ {
+ return lhs.p_map == rhs.p_map && lhs.p_node == rhs.p_node;
+ }
+
+ friend bool operator != (const iterator& lhs, const iterator& rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+ private:
+
+ // Pointer to map associated with this iterator
+ imap* p_map;
+
+ // Pointer to the current node for this iterator
+ Node* p_node;
+ };
+
+ friend class iterator;
+
+ //*************************************************************************
+ /// const_iterator
+ //*************************************************************************
+ class const_iterator : public std::iterator<std::bidirectional_iterator_tag, const value_type>
+ {
+ public:
+
+ friend class imap;
+
+ const_iterator()
+ : p_map(nullptr)
+ , p_node(nullptr)
+ {
+ }
+
+ const_iterator(const imap& map)
+ : p_map(&map)
+ , p_node(nullptr)
+ {
+ }
+
+ const_iterator(const imap& map, const Node* node)
+ : p_map(&map)
+ , p_node(node)
+ {
+ }
+
+ const_iterator(const typename imap::iterator& other)
+ : p_map(other.p_map)
+ , p_node(other.p_node)
+ {
+ }
+
+ const_iterator(const const_iterator& other)
+ : p_map(other.p_map)
+ , p_node(other.p_node)
+ {
+ }
+
+ ~const_iterator()
+ {
+ }
+
+ const_iterator& operator ++()
+ {
+ p_map->next_node(p_node);
+ return *this;
+ }
+
+ const_iterator operator ++(int)
+ {
+ const_iterator temp(*this);
+ p_map->next_node(p_node);
+ return temp;
+ }
+
+ const_iterator& operator --()
+ {
+ p_map->prev_node(p_node);
+ return *this;
+ }
+
+ const_iterator operator --(int)
+ {
+ const_iterator temp(*this);
+ p_map->prev_node(p_node);
+ return temp;
+ }
+
+ const_iterator operator =(const const_iterator& other)
+ {
+ p_map = other.p_map;
+ p_node = other.p_node;
+ return *this;
+ }
+
+ const_reference operator *() const
+ {
+ return imap::data_cast(p_node)->value;
+ }
+
+ const_pointer operator &() const
+ {
+ return imap::data_cast(p_node)->value;
+ }
+
+ const_pointer operator ->() const
+ {
+ return &(imap::data_cast(p_node)->value);
+ }
+
+ friend bool operator == (const const_iterator& lhs, const const_iterator& rhs)
+ {
+ return lhs.p_map == rhs.p_map && lhs.p_node == rhs.p_node;
+ }
+
+ friend bool operator != (const const_iterator& lhs, const const_iterator& rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+ private:
+ // Pointer to map associated with this iterator
+ const imap* p_map;
+
+ // Pointer to the current node for this iterator
+ const Node* p_node;
+ };
+
+ friend class const_iterator;
+
+ typedef typename std::iterator_traits<iterator>::difference_type difference_type;
+
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+
+
+ //*************************************************************************
+ /// Gets the beginning of the map.
+ //*************************************************************************
+ iterator begin()
+ {
+ return iterator(*this, find_limit_node(root_node, kLeft));
+ }
+
+ //*************************************************************************
+ /// Gets the beginning of the map.
+ //*************************************************************************
+ const_iterator begin() const
+ {
+ return const_iterator(*this, find_limit_node(root_node, kLeft));
+ }
+
+ //*************************************************************************
+ /// Gets the end of the map.
+ //*************************************************************************
+ iterator end()
+ {
+ return iterator(*this);
+ }
+
+ //*************************************************************************
+ /// Gets the end of the map.
+ //*************************************************************************
+ const_iterator end() const
+ {
+ return const_iterator(*this);
+ }
+
+ //*************************************************************************
+ /// Gets the beginning of the map.
+ //*************************************************************************
+ const_iterator cbegin() const
+ {
+ return const_iterator(*this, find_limit_node(root_node, kLeft));
+ }
+
+ //*************************************************************************
+ /// Gets the end of the map.
+ //*************************************************************************
+ const_iterator cend() const
+ {
+ return const_iterator(*this);
+ }
+
+ //*************************************************************************
+ /// Gets the reverse beginning of the list.
+ //*************************************************************************
+ reverse_iterator rbegin()
+ {
+ return reverse_iterator(iterator(*this));
+ }
+
+ //*************************************************************************
+ /// Gets the reverse beginning of the list.
+ //*************************************************************************
+ const_reverse_iterator rbegin() const
+ {
+ return const_reverse_iterator(const_iterator(*this));
+ }
+
+ //*************************************************************************
+ /// Gets the reverse end of the list.
+ //*************************************************************************
+ reverse_iterator rend()
+ {
+ return reverse_iterator(iterator(*this, find_limit_node(root_node, kLeft)));
+ }
+
+ //*************************************************************************
+ /// Gets the reverse end of the list.
+ //*************************************************************************
+ const_reverse_iterator rend() const
+ {
+ return const_reverse_iterator(iterator(*this, find_limit_node(root_node, kLeft)));
+ }
+
+ //*************************************************************************
+ /// Gets the reverse beginning of the list.
+ //*************************************************************************
+ const_reverse_iterator crbegin() const
+ {
+ return const_reverse_iterator(const_iterator(*this));
+ }
+
+ //*************************************************************************
+ /// Gets the reverse end of the list.
+ //*************************************************************************
+ const_reverse_iterator crend() const
+ {
+ return const_reverse_iterator(const_iterator(*this, find_limit_node(root_node, kLeft)));
+ }
+
+ //*********************************************************************
+ /// Returns a reference to the value at index 'key'
+ ///\param i The index.
+ ///\return A reference to the value at index 'key'
+ //*********************************************************************
+ mapped_type& operator [](const key_value_parameter_t& key)
+ {
+ iterator i_element = find(key);
+
+ if (!i_element.p_node)
+ {
+ // Doesn't exist, so create a new one.
+ i_element = insert(std::make_pair(key, mapped_type())).first;
+ }
+
+ return i_element->second;
+ }
+
+ //*********************************************************************
+ /// Returns a reference to the value at index 'key'
+ /// If asserts or exceptions are enabled, emits an etl::lookup_out_of_bounds if the key is not in the range.
+ ///\param i The index.
+ ///\return A reference to the value at index 'key'
+ //*********************************************************************
+ mapped_type& at(const key_value_parameter_t& key)
+ {
+ iterator i_element = find(key);
+
+ ETL_ASSERT(i_element.p_node != nullptr, ETL_ERROR(map_out_of_bounds));
+
+ return i_element->second;
+ }
+
+ //*********************************************************************
+ /// Returns a const reference to the value at index 'key'
+ /// If asserts or exceptions are enabled, emits an etl::lookup_out_of_bounds if the key is not in the range.
+ ///\param i The index.
+ ///\return A const reference to the value at index 'key'
+ //*********************************************************************
+ const mapped_type& at(const key_value_parameter_t& key) const
+ {
+ const_iterator i_element = find(key);
+
+ ETL_ASSERT(i_element.p_node != nullptr, ETL_ERROR(map_out_of_bounds));
+
+ return i_element->second;
+ }
+
+ //*********************************************************************
+ /// Assigns values to the map.
+ /// If asserts or exceptions are enabled, emits map_full if the map does not have enough free space.
+ /// If asserts or exceptions are enabled, emits map_iterator if the iterators are reversed.
+ ///\param first The iterator to the first element.
+ ///\param last The iterator to the last element + 1.
+ //*********************************************************************
+ template <typename TIterator>
+ void assign(TIterator first, TIterator last)
+ {
+ initialise();
+ insert(first, last);
+ }
+
+ //*************************************************************************
+ /// Clears the map.
+ //*************************************************************************
+ void clear()
+ {
+ initialise();
+ }
+
+ //*********************************************************************
+ /// Counts the number of elements that contain the key specified.
+ ///\param key The key to search for.
+ ///\return 1 if element was found, 0 otherwise.
+ //*********************************************************************
+ size_type count(const key_value_parameter_t& key) const
+ {
+ return find_node(root_node, key) ? 1 : 0;
+ }
+
+ //*************************************************************************
+ /// Returns two iterators with bounding (lower bound, upper bound) the key
+ /// provided
+ //*************************************************************************
+ std::pair<iterator, iterator> equal_range(const key_value_parameter_t& key)
+ {
+ return std::make_pair<iterator, iterator>(
+ iterator(*this, find_lower_node(root_node, key)),
+ iterator(*this, find_upper_node(root_node, key)));
+ }
+
+ //*************************************************************************
+ /// Returns two const iterators with bounding (lower bound, upper bound)
+ /// the key provided.
+ //*************************************************************************
+ std::pair<const_iterator, const_iterator> equal_range(const key_value_parameter_t& key) const
+ {
+ return std::make_pair<const_iterator, const_iterator>(
+ const_iterator(*this, find_lower_node(root_node, key)),
+ const_iterator(*this, find_upper_node(root_node, key)));
+ }
+
+ //*************************************************************************
+ /// Erases the value at the specified position.
+ //*************************************************************************
+ void erase(iterator position)
+ {
+ // Remove the node by its key
+ erase((*position).first);
+ }
+
+ //*************************************************************************
+ /// Erases the value at the specified position.
+ //*************************************************************************
+ iterator erase(const_iterator position)
+ {
+ // Find the parent node to be removed
+ Node*& reference_node = find_node(root_node, position.p_node);
+ iterator next(*this, reference_node);
+ ++next;
+
+ remove_node(root_node, (*position).first);
+
+ return next;
+ }
+
+ //*************************************************************************
+ // Erase the key specified.
+ //*************************************************************************
+ size_type erase(const key_value_parameter_t& key)
+ {
+ // Return 1 if key value was found and removed
+ return remove_node(root_node, key) ? 1 : 0;
+ }
+
+ //*************************************************************************
+ /// Erases a range of elements.
+ //*************************************************************************
+ iterator erase(iterator first, iterator last)
+ {
+ iterator next;
+ while (first != last)
+ {
+ next = erase(const_iterator(first++));
+ }
+
+ return next;
+ }
+
+ //*************************************************************************
+ /// Erases a range of elements.
+ //*************************************************************************
+ iterator erase(const_iterator first, const_iterator last)
+ {
+ iterator next;
+ while (first != last)
+ {
+ next = erase(first++);
+ }
+
+ return next;
+ }
+
+ //*********************************************************************
+ /// Finds an element.
+ ///\param key The key to search for.
+ ///\return An iterator pointing to the element or end() if not found.
+ //*********************************************************************
+ iterator find(const key_value_parameter_t& key)
+ {
+ return iterator(*this, find_node(root_node, key));
+ }
+
+ //*********************************************************************
+ /// Finds an element.
+ ///\param key The key to search for.
+ ///\return An iterator pointing to the element or end() if not found.
+ //*********************************************************************
+ const_iterator find(const key_value_parameter_t& key) const
+ {
+ return const_iterator(*this, find_node(root_node, key));
+ }
+
+ //*********************************************************************
+ /// Inserts a value to the map.
+ /// If asserts or exceptions are enabled, emits map_full if the map is already full.
+ ///\param value The value to insert.
+ //*********************************************************************
+ std::pair<iterator, bool> insert(const value_type& value)
+ {
+ // Default to no inserted node
+ Node* inserted_node = nullptr;
+ bool inserted = false;
+
+ ETL_ASSERT(!full(), ETL_ERROR(map_full));
+
+ // Get next available free node
+ Data_Node& node = allocate_data_node(value);
+
+ // Obtain the inserted node (might be nullptr if node was a duplicate)
+ inserted_node = insert_node(root_node, node);
+ inserted = inserted_node == &node;
+
+ // Insert node into tree and return iterator to new node location in tree
+ return std::make_pair(iterator(*this, inserted_node), inserted);
+ }
+
+ //*********************************************************************
+ /// Inserts a value to the map starting at the position recommended.
+ /// If asserts or exceptions are enabled, emits map_full if the map is already full.
+ ///\param position The position that would precede the value to insert.
+ ///\param value The value to insert.
+ //*********************************************************************
+ iterator insert(iterator, const value_type& value)
+ {
+ // Default to no inserted node
+ Node* inserted_node = nullptr;
+
+ ETL_ASSERT(!full(), ETL_ERROR(map_full));
+
+ // Get next available free node
+ Data_Node& node = allocate_data_node(value);
+
+ // Obtain the inserted node (might be nullptr if node was a duplicate)
+ inserted_node = insert_node(root_node, node);
+
+ // Insert node into tree and return iterator to new node location in tree
+ return iterator(*this, inserted_node);
+ }
+
+ //*********************************************************************
+ /// Inserts a value to the map starting at the position recommended.
+ /// If asserts or exceptions are enabled, emits map_full if the map is already full.
+ ///\param position The position that would precede the value to insert.
+ ///\param value The value to insert.
+ //*********************************************************************
+ iterator insert(const_iterator, const value_type& value)
+ {
+ // Default to no inserted node
+ Node* inserted_node = nullptr;
+
+ ETL_ASSERT(!full(), ETL_ERROR(map_full));
+
+ // Get next available free node
+ Data_Node& node = allocate_data_node(value);
+
+ // Obtain the inserted node (might be nullptr if node was a duplicate)
+ inserted_node = insert_node(root_node, node);
+
+ // Insert node into tree and return iterator to new node location in tree
+ return iterator(*this, inserted_node);
+ }
+
+ //*********************************************************************
+ /// Inserts a range of values to the map.
+ /// If asserts or exceptions are enabled, emits map_full if the map does not have enough free space.
+ ///\param position The position to insert at.
+ ///\param first The first element to add.
+ ///\param last The last + 1 element to add.
+ //*********************************************************************
+ template <class TIterator>
+ void insert(TIterator first, TIterator last)
+ {
+ while (first != last)
+ {
+ insert(*first++);
+ }
+ }
+
+ //*********************************************************************
+ /// Returns an iterator pointing to the first element in the container
+ /// whose key is not considered to go before the key provided or end()
+ /// if all keys are considered to go before the key provided.
+ ///\return An iterator pointing to the element not before key or end()
+ //*********************************************************************
+ iterator lower_bound(const key_value_parameter_t& key)
+ {
+ return iterator(*this, find_lower_node(root_node, key));
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator pointing to the first element in the
+ /// container whose key is not considered to go before the key provided
+ /// or end() if all keys are considered to go before the key provided.
+ ///\return An const_iterator pointing to the element not before key or end()
+ //*********************************************************************
+ const_iterator lower_bound(const key_value_parameter_t& key) const
+ {
+ return const_iterator(*this, find_lower_node(root_node, key));
+ }
+
+ //*********************************************************************
+ /// Returns an iterator pointing to the first element in the container
+ /// whose key is not considered to go after the key provided or end()
+ /// if all keys are considered to go after the key provided.
+ ///\return An iterator pointing to the element after key or end()
+ //*********************************************************************
+ iterator upper_bound(const key_value_parameter_t& key)
+ {
+ return iterator(*this, find_upper_node(root_node, key));
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator pointing to the first element in the
+ /// container whose key is not considered to go after the key provided
+ /// or end() if all keys are considered to go after the key provided.
+ ///\return An const_iterator pointing to the element after key or end()
+ //*********************************************************************
+ const_iterator upper_bound(const key_value_parameter_t& key) const
+ {
+ return const_iterator(*this, find_upper_node(root_node, key));
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ imap& operator = (const imap& rhs)
+ {
+ // Skip if doing self assignment
+ if (this != &rhs)
+ {
+ assign(rhs.cbegin(), rhs.cend());
+ }
+
+ return *this;
+ }
+
+ protected:
+
+ //*************************************************************************
+ /// Constructor.
+ //*************************************************************************
+ imap(ipool<Data_Node>& node_pool, size_t max_size_)
+ : map_base(max_size_)
+ , p_node_pool(&node_pool)
+ {
+ }
+
+ //*************************************************************************
+ /// Initialise the map.
+ //*************************************************************************
+ void initialise()
+ {
+ if (!empty())
+ {
+ p_node_pool->release_all();
+ }
+
+ current_size = 0;
+ root_node = nullptr;
+ }
+
+ private:
+
+ //*************************************************************************
+ /// Allocate a Data_Node.
+ //*************************************************************************
+ Data_Node& allocate_data_node(value_type value) const
+ {
+ return *(p_node_pool->allocate(Data_Node(value)));
+ }
+
+ //*************************************************************************
+ /// Destroy a Data_Node.
+ //*************************************************************************
+ void destroy_data_node(Data_Node& node) const
+ {
+ p_node_pool->release(&node);
+ }
+
+ //*************************************************************************
+ /// Find the value matching the node provided
+ //*************************************************************************
+ Node* find_node(Node* position, const key_value_parameter_t& key)
+ {
+ Node* found = position;
+ while (found)
+ {
+ // Downcast found to Data_Node class for comparison and other operations
+ Data_Node& found_data_node = imap::data_cast(*found);
+
+ // Compare the node value to the current position value
+ if (node_comp(key, found_data_node))
+ {
+ // Keep searching for the node on the left
+ found = found->children[kLeft];
+ }
+ else if (node_comp(found_data_node, key))
+ {
+ // Keep searching for the node on the right
+ found = found->children[kRight];
+ }
+ else
+ {
+ // Node that matches the key provided was found, exit loop
+ break;
+ }
+ }
+
+ // Return the node found (might be nullptr)
+ return found;
+ }
+
+ //*************************************************************************
+ /// Find the value matching the node provided
+ //*************************************************************************
+ const Node* find_node(const Node* position, const key_value_parameter_t& key) const
+ {
+ const Node* found = position;
+ while (found)
+ {
+ // Downcast found to Data_Node class for comparison and other operations
+ const Data_Node& found_data_node = imap::data_cast(*found);
+
+ // Compare the node value to the current position value
+ if (node_comp(key, found_data_node))
+ {
+ // Keep searching for the node on the left
+ found = found->children[kLeft];
+ }
+ else if (node_comp(found_data_node, key))
+ {
+ // Keep searching for the node on the right
+ found = found->children[kRight];
+ }
+ else
+ {
+ // Node that matches the key provided was found, exit loop
+ break;
+ }
+ }
+
+ // Return the node found (might be nullptr)
+ return found;
+ }
+
+ //*************************************************************************
+ /// Find the reference node matching the node provided
+ //*************************************************************************
+ Node*& find_node(Node*& position, const Node* node)
+ {
+ Node* found = position;
+ while (found)
+ {
+ if (found->children[kLeft] == node)
+ {
+ return found->children[kLeft];
+ }
+ else if (found->children[kRight] == node)
+ {
+ return found->children[kRight];
+ }
+ else
+ {
+ // Downcast found to Data_Node class for comparison and other operations
+ Data_Node& found_data_node = imap::data_cast(*found);
+ const Data_Node& data_node = imap::data_cast(*node);
+
+ // Compare the node value to the current position value
+ if (node_comp(data_node, found_data_node))
+ {
+ // Keep searching for the node on the left
+ found = found->children[kLeft];
+ }
+ else if (node_comp(found_data_node, data_node))
+ {
+ // Keep searching for the node on the right
+ found = found->children[kRight];
+ }
+ else
+ {
+ // Return position provided (it matches the node)
+ return position;
+ }
+ }
+ }
+
+ // Return root node if nothing was found
+ return root_node;
+ }
+
+ //*************************************************************************
+ /// Find the parent node that contains the node provided in its left or
+ /// right tree
+ //*************************************************************************
+ Node* find_parent_node(Node* position, const Node* node)
+ {
+ // Default to no parent node found
+ Node* found = nullptr;
+
+ // If the position provided is the same as the node then there is no parent
+ if (position && node && position != node)
+ {
+ while (position)
+ {
+ // Is this position not the parent of the node we are looking for?
+ if (position->children[kLeft] != node &&
+ position->children[kRight] != node)
+ {
+ // Downcast node and position to Data_Node references for key comparisons
+ const Data_Node& node_data_node = imap::data_cast(*node);
+ Data_Node& position_data_node = imap::data_cast(*position);
+ // Compare the node value to the current position value
+ if (node_comp(node_data_node, position_data_node))
+ {
+ // Keep looking for parent on the left
+ position = position->children[kLeft];
+ }
+ else if (node_comp(position_data_node, node_data_node))
+ {
+ // Keep looking for parent on the right
+ position = position->children[kRight];
+ }
+ }
+ else
+ {
+ // Return the current position as the parent node found
+ found = position;
+
+ // Parent node found, exit loop
+ break;
+ }
+ }
+ }
+
+ // Return the parent node found (might be nullptr)
+ return found;
+ }
+
+ //*************************************************************************
+ /// Find the parent node that contains the node provided in its left or
+ /// right tree
+ //*************************************************************************
+ const Node* find_parent_node(const Node* position, const Node* node) const
+ {
+ // Default to no parent node found
+ const Node* found = nullptr;
+
+ // If the position provided is the same as the node then there is no parent
+ if (position && node && position != node)
+ {
+ while (position)
+ {
+ // Is this position not the parent of the node we are looking for?
+ if (position->children[kLeft] != node &&
+ position->children[kRight] != node)
+ {
+ // Downcast node and position to Data_Node references for key comparisons
+ const Data_Node& node_data_node = imap::data_cast(*node);
+ const Data_Node& position_data_node = imap::data_cast(*position);
+ // Compare the node value to the current position value
+ if (node_comp(node_data_node, position_data_node))
+ {
+ // Keep looking for parent on the left
+ position = position->children[kLeft];
+ }
+ else if (node_comp(position_data_node, node_data_node))
+ {
+ // Keep looking for parent on the right
+ position = position->children[kRight];
+ }
+ }
+ else
+ {
+ // Return the current position as the parent node found
+ found = position;
+
+ // Parent node found, exit loop
+ break;
+ }
+ }
+ }
+
+ // Return the parent node found (might be nullptr)
+ return found;
+ }
+
+ //*************************************************************************
+ /// Find the node whose key is not considered to go before the key provided
+ //*************************************************************************
+ Node* find_lower_node(Node* position, const key_value_parameter_t& key) const
+ {
+ // Something at this position? keep going
+ Node* lower_node = position;
+ while (lower_node)
+ {
+ // Downcast lower node to Data_Node reference for key comparisons
+ Data_Node& data_node = imap::data_cast(*lower_node);
+ // Compare the key value to the current lower node key value
+ if (node_comp(key, data_node))
+ {
+ if (lower_node->children[kLeft])
+ {
+ lower_node = lower_node->children[kLeft];
+ }
+ else
+ {
+ // Found lowest node
+ break;
+ }
+ }
+ else if (node_comp(data_node, key))
+ {
+ lower_node = lower_node->children[kRight];
+ }
+ else
+ {
+ // Found equal node
+ break;
+ }
+ }
+
+ // Return the lower_node position found
+ return lower_node;
+ }
+
+ //*************************************************************************
+ /// Find the node whose key is considered to go after the key provided
+ //*************************************************************************
+ Node* find_upper_node(Node* position, const key_value_parameter_t& key) const
+ {
+ // Keep track of parent of last upper node
+ Node* upper_node = nullptr;
+ // Start with position provided
+ Node* node = position;
+ while (node)
+ {
+ // Downcast position to Data_Node reference for key comparisons
+ Data_Node& data_node = imap::data_cast(*node);
+ // Compare the key value to the current upper node key value
+ if (node_comp(key, data_node))
+ {
+ upper_node = node;
+ node = node->children[kLeft];
+ }
+ else if (node_comp(data_node, key))
+ {
+ node = node->children[kRight];
+ }
+ else if (node->children[kRight])
+ {
+ upper_node = find_limit_node(node->children[kRight], kLeft);
+ break;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ // Return the upper node position found (might be nullptr)
+ return upper_node;
+ }
+
+ //*************************************************************************
+ /// Insert a node.
+ //*************************************************************************
+ Node* insert_node(Node*& position, Data_Node& node)
+ {
+ // Find the location where the node belongs
+ Node* found = position;
+
+ // Was position provided not empty? then find where the node belongs
+ if (position)
+ {
+ // Find the critical parent node (default to nullptr)
+ Node* critical_parent_node = nullptr;
+ Node* critical_node = root_node;
+
+ while (found)
+ {
+ // Search for critical weight node (all nodes whose weight factor
+ // is set to kNeither (balanced)
+ if (kNeither != found->weight)
+ {
+ critical_node = found;
+ }
+
+ // Downcast found to Data_Node class for comparison and other operations
+ Data_Node& found_data_node = imap::data_cast(*found);
+
+ // Is the node provided to the left of the current position?
+ if (node_comp(node, found_data_node))
+ {
+ // Update direction taken to insert new node in parent node
+ found->dir = kLeft;
+ }
+ // Is the node provided to the right of the current position?
+ else if (node_comp(found_data_node, node))
+ {
+ // Update direction taken to insert new node in parent node
+ found->dir = kRight;
+ }
+ else
+ {
+ // Update direction taken to insert new node in parent node
+ found->dir = kNeither;
+
+ // Clear critical node value to skip weight step below
+ critical_node = nullptr;
+
+ // Destroy the node provided (its a duplicate)
+ destroy_data_node(node);
+
+ // Exit loop, duplicate node found
+ break;
+ }
+
+ // Is there a child of this parent node?
+ if (found->children[found->dir])
+ {
+ // Will this node be the parent of the next critical node whose
+ // weight factor is set to kNeither (balanced)?
+ if (kNeither != found->children[found->dir]->weight)
+ {
+ critical_parent_node = found;
+ }
+
+ // Keep looking for empty spot to insert new node
+ found = found->children[found->dir];
+ }
+ else
+ {
+ // Attatch node to right
+ attach_node(found->children[found->dir], node);
+
+ // Return newly added node
+ found = found->children[found->dir];
+
+ // Exit loop
+ break;
+ }
+ }
+
+ // Was a critical node found that should be checked for balance?
+ if (critical_node)
+ {
+ if (critical_parent_node == nullptr && critical_node == root_node)
+ {
+ balance_node(root_node);
+ }
+ else if (critical_parent_node == nullptr && critical_node == position)
+ {
+ balance_node(position);
+ }
+ else
+ {
+ balance_node(critical_parent_node->children[critical_parent_node->dir]);
+ }
+ }
+ }
+ else
+ {
+ // Attatch node to current position
+ attach_node(position, node);
+
+ // Return newly added node at current position
+ found = position;
+ }
+
+ // Return the node found (might be nullptr)
+ return found;
+ }
+
+ //*************************************************************************
+ /// Find the next node in sequence from the node provided
+ //*************************************************************************
+ void next_node(Node*&position)
+ {
+ if (position)
+ {
+ // Is there a tree on the right? then find the minimum of that tree
+ if (position->children[kRight])
+ {
+ // Return minimum node found
+ position = find_limit_node(position->children[kRight], kLeft);
+ }
+ // Otherwise find the parent of this node
+ else
+ {
+ // Start with current position as parent
+ Node* parent = position;
+ do {
+ // Update current position as previous parent
+ position = parent;
+ // Find parent of current position
+ parent = find_parent_node(root_node, position);
+ // Repeat while previous position was on right side of parent tree
+ } while (parent && parent->children[kRight] == position);
+
+ // Set parent node as the next position
+ position = parent;
+ }
+ }
+ }
+
+ //*************************************************************************
+ /// Find the next node in sequence from the node provided
+ //*************************************************************************
+ void next_node(const Node*& position) const
+ {
+ if (position)
+ {
+ // Is there a tree on the right? then find the minimum of that tree
+ if (position->children[kRight])
+ {
+ // Return minimum node found
+ position = find_limit_node(position->children[kRight], kLeft);
+ }
+ // Otherwise find the parent of this node
+ else
+ {
+ // Start with current position as parent
+ const Node* parent = position;
+ do {
+ // Update current position as previous parent
+ position = parent;
+ // Find parent of current position
+ parent = find_parent_node(root_node, position);
+ // Repeat while previous position was on right side of parent tree
+ } while (parent && parent->children[kRight] == position);
+
+ // Set parent node as the next position
+ position = parent;
+ }
+ }
+ }
+
+ //*************************************************************************
+ /// Find the previous node in sequence from the node provided
+ //*************************************************************************
+ void prev_node(Node*&position)
+ {
+ // If starting at the terminal end, the previous node is the maximum node
+ // from the root
+ if (!position)
+ {
+ position = find_limit_node(root_node, kRight);
+ }
+ else
+ {
+ // Is there a tree on the left? then find the maximum of that tree
+ if (position->children[kLeft])
+ {
+ // Return maximum node found
+ position = find_limit_node(position->children[kLeft], kRight);
+ }
+ // Otherwise find the parent of this node
+ else
+ {
+ // Start with current position as parent
+ Node* parent = position;
+ do {
+ // Update current position as previous parent
+ position = parent;
+ // Find parent of current position
+ parent = find_parent_node(root_node, position);
+ // Repeat while previous position was on left side of parent tree
+ } while (parent && parent->children[kLeft] == position);
+
+ // Set parent node as the next position
+ position = parent;
+ }
+ }
+ }
+
+ //*************************************************************************
+ /// Find the previous node in sequence from the node provided
+ //*************************************************************************
+ void prev_node(const Node*& position) const
+ {
+ // If starting at the terminal end, the previous node is the maximum node
+ // from the root
+ if (!position)
+ {
+ position = find_limit_node(root_node, kRight);
+ }
+ else
+ {
+ // Is there a tree on the left? then find the maximum of that tree
+ if (position->children[kLeft])
+ {
+ // Return maximum node found
+ position = find_limit_node(position->children[kLeft], kRight);
+ }
+ // Otherwise find the parent of this node
+ else
+ {
+ // Start with current position as parent
+ const Node* parent = position;
+ do {
+ // Update current position as previous parent
+ position = parent;
+ // Find parent of current position
+ parent = find_parent_node(root_node, position);
+ // Repeat while previous position was on left side of parent tree
+ } while (parent && parent->children[kLeft] == position);
+
+ // Set parent node as the next position
+ position = parent;
+ }
+ }
+ }
+
+ //*************************************************************************
+ /// Remove the node specified from somewhere starting at the position
+ /// provided
+ //*************************************************************************
+ Node* remove_node(Node*& position, const key_value_parameter_t& key)
+ {
+ // Step 1: Find the target node that matches the key provided, the
+ // replacement node (might be the same as target node), and the critical
+ // node to start rebalancing the tree from (up to the replacement node)
+ Node* found_parent = nullptr;
+ Node* found = nullptr;
+ Node* replace_parent = nullptr;
+ Node* replace = position;
+ Node* balance_parent = nullptr;
+ Node* balance = root_node;
+ while (replace)
+ {
+ // Downcast found to Data_Node class for comparison and other operations
+ Data_Node& replace_data_node = imap::data_cast(*replace);
+
+ // Compare the key provided to the replace data node key
+ if (node_comp(key, replace_data_node))
+ {
+ // Update the direction to the target/replace node
+ replace->dir = kLeft;
+ }
+ else if (node_comp(replace_data_node, key))
+ {
+ // Update the direction to the target/replace node
+ replace->dir = kRight;
+ }
+ else
+ {
+ // Update the direction to the replace node (target node found here)
+ replace->dir = replace->children[kLeft] ? kLeft : kRight;
+
+ // Note the target node was found (and its parent)
+ found_parent = replace_parent;
+ found = replace;
+ }
+ // Replacement node found if its missing a child in the replace->dir
+ // value set above
+ if (replace->children[replace->dir] == nullptr)
+ {
+ // Exit loop once replace node is found (target might not have been)
+ break;
+ }
+
+ // If replacement node weight is kNeither or we are taking the shorter
+ // path of replacement node and our sibling (on longer path) is
+ // balanced then we need to update the balance node to match this
+ // replacement node but all our ancestors will not require rebalancing
+ if ((replace->weight == kNeither) ||
+ (replace->weight == (1 - replace->dir) &&
+ replace->children[1 - replace->dir]->weight == kNeither))
+ {
+ // Update balance node (and its parent) to replacement node
+ balance_parent = replace_parent;
+ balance = replace;
+ }
+
+ // Keep searching for the replacement node
+ replace_parent = replace;
+ replace = replace->children[replace->dir];
+ }
+
+ // If target node was found, proceed with rebalancing and replacement
+ if (found)
+ {
+ // Step 2: Update weights from critical node to replacement parent node
+ while (balance)
+ {
+ if (balance->children[balance->dir] == nullptr)
+ {
+ break;
+ }
+
+ if (balance->weight == kNeither)
+ {
+ balance->weight = 1 - balance->dir;
+ }
+ else if (balance->weight == balance->dir)
+ {
+ balance->weight = kNeither;
+ }
+ else
+ {
+ int weight = balance->children[1 - balance->dir]->weight;
+ // Perform a 3 node rotation if weight is same as balance->dir
+ if (weight == balance->dir)
+ {
+ // Is the root node being rebalanced (no parent)
+ if (balance_parent == nullptr)
+ {
+ rotate_3node(root_node, 1 - balance->dir,
+ balance->children[1 - balance->dir]->children[balance->dir]->weight);
+ }
+ else
+ {
+ rotate_3node(balance_parent->children[balance_parent->dir], 1 - balance->dir,
+ balance->children[1 - balance->dir]->children[balance->dir]->weight);
+ }
+ }
+ // Already balanced, rebalance and make it heavy in opposite
+ // direction of the node being removed
+ else if (weight == kNeither)
+ {
+ // Is the root node being rebalanced (no parent)
+ if (balance_parent == nullptr)
+ {
+ rotate_2node(root_node, 1 - balance->dir);
+ root_node->weight = balance->dir;
+ }
+ else
+ {
+ rotate_2node(balance_parent->children[balance_parent->dir], 1 - balance->dir);
+ balance_parent->children[balance_parent->dir]->weight = balance->dir;
+ }
+ // Update balance node weight in opposite direction of node removed
+ balance->weight = 1 - balance->dir;
+ }
+ // Rebalance and leave it balanced
+ else
+ {
+ // Is the root node being rebalanced (no parent)
+ if (balance_parent == nullptr)
+ {
+ rotate_2node(root_node, 1 - balance->dir);
+ }
+ else
+ {
+ rotate_2node(balance_parent->children[balance_parent->dir], 1 - balance->dir);
+ }
+ }
+
+ // Is balance node the same as the target node found? then update
+ // its parent after the rotation performed above
+ if (balance == found)
+ {
+ if (balance_parent)
+ {
+ found_parent = balance_parent->children[balance_parent->dir];
+ // Update dir since it is likely stale
+ found_parent->dir = found_parent->children[kLeft] == found ? kLeft : kRight;
+ }
+ else
+ {
+ found_parent = root_node;
+ root_node->dir = root_node->children[kLeft] == found ? kLeft : kRight;
+ }
+ }
+ }
+
+ // Next balance node to consider
+ balance_parent = balance;
+ balance = balance->children[balance->dir];
+ } // while(balance)
+
+ // Step 3: Swap found node with replacement node
+ if (found_parent)
+ {
+ // Handle traditional case
+ detach_node(found_parent->children[found_parent->dir],
+ replace_parent->children[replace_parent->dir]);
+ }
+ // Handle root node removal
+ else
+ {
+ // Valid replacement node for root node being removed?
+ if (replace_parent)
+ {
+ detach_node(root_node, replace_parent->children[replace_parent->dir]);
+ }
+ else
+ {
+ // Target node and replacement node are both root node
+ detach_node(root_node, root_node);
+ }
+ }
+
+ // Downcast found into data node
+ Data_Node& found_data_node = imap::data_cast(*found);
+
+ // One less.
+ --current_size;
+
+ // Destroy the node removed
+ destroy_data_node(found_data_node);
+ } // if(found)
+
+ // Return node found (might be nullptr)
+ return found;
+ }
+
+ // Disable copy construction.
+ imap(const imap&);
+ };
+}
+
+//***************************************************************************
+/// Equal operator.
+///\param lhs Reference to the first lookup.
+///\param rhs Reference to the second lookup.
+///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
+///\ingroup lookup
+//***************************************************************************
+template <typename TKey, typename TMapped, typename TKeyCompare>
+bool operator ==(const etl::imap<TKey, TMapped, TKeyCompare>& lhs, const etl::imap<TKey, TMapped, TKeyCompare>& rhs)
+{
+ return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin());
+}
+
+//***************************************************************************
+/// Not equal operator.
+///\param lhs Reference to the first lookup.
+///\param rhs Reference to the second lookup.
+///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
+///\ingroup lookup
+//***************************************************************************
+template <typename TKey, typename TMapped, typename TKeyCompare>
+bool operator !=(const etl::imap<TKey, TMapped, TKeyCompare>& lhs, const etl::imap<TKey, TMapped, TKeyCompare>& rhs)
+{
+ return !(lhs == rhs);
+}
+
+//*************************************************************************
+/// Less than operator.
+///\param lhs Reference to the first list.
+///\param rhs Reference to the second list.
+///\return <b>true</b> if the first list is lexicographically less than the
+/// second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename TKey, typename TMapped, typename TKeyCompare>
+bool operator <(const etl::imap<TKey, TMapped, TKeyCompare>& lhs, const etl::imap<TKey, TMapped, TKeyCompare>& rhs)
+{
+ return std::lexicographical_compare(lhs.begin(),
+ lhs.end(),
+ rhs.begin(),
+ rhs.end());
+}
+
+//*************************************************************************
+/// Greater than operator.
+///\param lhs Reference to the first list.
+///\param rhs Reference to the second list.
+///\return <b>true</b> if the first list is lexicographically greater than the
+/// second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename TKey, typename TMapped, typename TKeyCompare>
+bool operator >(const etl::imap<TKey, TMapped, TKeyCompare>& lhs, const etl::imap<TKey, TMapped, TKeyCompare>& rhs)
+{
+ return (rhs < lhs);
+}
+
+//*************************************************************************
+/// Less than or equal operator.
+///\param lhs Reference to the first list.
+///\param rhs Reference to the second list.
+///\return <b>true</b> if the first list is lexicographically less than or equal
+/// to the second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename TKey, typename TMapped, typename TKeyCompare>
+bool operator <=(const etl::imap<TKey, TMapped, TKeyCompare>& lhs, const etl::imap<TKey, TMapped, TKeyCompare>& rhs)
+{
+ return !(lhs > rhs);
+}
+
+//*************************************************************************
+/// Greater than or equal operator.
+///\param lhs Reference to the first list.
+///\param rhs Reference to the second list.
+///\return <b>true</b> if the first list is lexicographically greater than or
+/// equal to the second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename TKey, typename TMapped, typename TKeyCompare>
+bool operator >=(const etl::imap<TKey, TMapped, TKeyCompare>& lhs, const etl::imap<TKey, TMapped, TKeyCompare>& rhs)
+{
+ return !(lhs < rhs);
+}
+
+#ifdef ETL_COMPILER_MICROSOFT
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#undef __ETL_IN_IMAP_H__
+
+#endif
diff --git a/lib/etl/imultimap.h b/lib/etl/imultimap.h
new file mode 100644
index 0000000..f88fd25
--- /dev/null
+++ b/lib/etl/imultimap.h
@@ -0,0 +1,1424 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove, rlindeman
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_IMULTIMAP__
+#define __ETL_IMULTIMAP__
+#define __ETL_IN_IMULTIMAP_H__
+
+#include <iterator>
+#include <algorithm>
+#include <functional>
+#include <stddef.h>
+
+#include "nullptr.h"
+#include "private/multimap_base.h"
+#include "type_traits.h"
+#include "parameter_type.h"
+#include "pool.h"
+#include "platform.h"
+
+#ifdef ETL_COMPILER_MICROSOFT
+#undef min
+#endif
+
+namespace etl
+{
+ //***************************************************************************
+ /// A templated base for all etl::multimap types.
+ ///\ingroup map
+ //***************************************************************************
+ template <typename TKey, typename TMapped, typename TKeyCompare>
+ class imultimap : public multimap_base
+ {
+ public:
+
+ typedef std::pair<const TKey, TMapped> value_type;
+ typedef const TKey key_type;
+ typedef TMapped mapped_type;
+ typedef TKeyCompare key_compare;
+ typedef value_type& reference;
+ typedef const value_type& const_reference;
+ typedef value_type* pointer;
+ typedef const value_type* const_pointer;
+ typedef size_t size_type;
+
+ //*************************************************************************
+ /// How to compare two key elements.
+ //*************************************************************************
+ struct key_comp
+ {
+ bool operator ()(const key_type& key1, const key_type& key2) const
+ {
+ return key_compare()(key1, key2);
+ }
+ };
+
+ //*************************************************************************
+ /// How to compare two value elements.
+ //*************************************************************************
+ struct value_comp
+ {
+ bool operator ()(const value_type& value1, const value_type& value2) const
+ {
+ return key_compare()(value1.first, value2.first);
+ }
+ };
+
+ protected:
+
+ //*************************************************************************
+ /// The data node element in the multimap.
+ //*************************************************************************
+ struct Data_Node : public Node
+ {
+ explicit Data_Node(value_type value)
+ : value(value)
+ {
+ }
+
+ value_type value;
+ };
+
+ /// Defines the key value parameter type
+ typedef typename parameter_type<TKey>::type key_value_parameter_t;
+
+ //*************************************************************************
+ /// How to compare node elements.
+ //*************************************************************************
+ bool node_comp(const Data_Node& node1, const Data_Node& node2) const
+ {
+ return key_compare()(node1.value.first, node2.value.first);
+ }
+
+ bool node_comp(const Data_Node& node, const key_value_parameter_t& key) const
+ {
+ return key_compare()(node.value.first, key);
+ }
+
+ bool node_comp(const key_value_parameter_t& key, const Data_Node& node) const
+ {
+ return key_compare()(key, node.value.first);
+ }
+
+ private:
+
+ /// The pool of data nodes used in the multimap.
+ ipool<Data_Node>* p_node_pool;
+
+ //*************************************************************************
+ /// Downcast a Node* to a Data_Node*
+ //*************************************************************************
+ static Data_Node* data_cast(Node* p_node)
+ {
+ return static_cast<Data_Node*>(p_node);
+ }
+
+ //*************************************************************************
+ /// Downcast a Node& to a Data_Node&
+ //*************************************************************************
+ static Data_Node& data_cast(Node& node)
+ {
+ return static_cast<Data_Node&>(node);
+ }
+
+ //*************************************************************************
+ /// Downcast a const Node* to a const Data_Node*
+ //*************************************************************************
+ static const Data_Node* data_cast(const Node* p_node)
+ {
+ return static_cast<const Data_Node*>(p_node);
+ }
+
+ //*************************************************************************
+ /// Downcast a const Node& to a const Data_Node&
+ //*************************************************************************
+ static const Data_Node& data_cast(const Node& node)
+ {
+ return static_cast<const Data_Node&>(node);
+ }
+
+ public:
+ //*************************************************************************
+ /// iterator.
+ //*************************************************************************
+ class iterator : public std::iterator<std::bidirectional_iterator_tag, value_type>
+ {
+ public:
+
+ friend class imultimap;
+
+ iterator()
+ : p_multimap(nullptr)
+ , p_node(nullptr)
+ {
+ }
+
+ iterator(imultimap& multimap)
+ : p_multimap(&multimap)
+ , p_node(nullptr)
+ {
+ }
+
+ iterator(imultimap& multimap, Node* node)
+ : p_multimap(&multimap)
+ , p_node(node)
+ {
+ }
+
+ iterator(const iterator& other)
+ : p_multimap(other.p_multimap)
+ , p_node(other.p_node)
+ {
+ }
+
+ ~iterator()
+ {
+ }
+
+ iterator& operator ++()
+ {
+ p_multimap->next_node(p_node);
+ return *this;
+ }
+
+ iterator operator ++(int)
+ {
+ iterator temp(*this);
+ p_multimap->next_node(p_node);
+ return temp;
+ }
+
+ iterator& operator --()
+ {
+ p_multimap->prev_node(p_node);
+ return *this;
+ }
+
+ iterator operator --(int)
+ {
+ iterator temp(*this);
+ p_multimap->prev_node(p_node);
+ return temp;
+ }
+
+ iterator operator =(const iterator& other)
+ {
+ p_multimap = other.p_multimap;
+ p_node = other.p_node;
+ return *this;
+ }
+
+ reference operator *()
+ {
+ return imultimap::data_cast(p_node)->value;
+ }
+
+ const_reference operator *() const
+ {
+ return imultimap::data_cast(p_node)->value;
+ }
+
+ pointer operator &()
+ {
+ return &(imultimap::data_cast(p_node)->value);
+ }
+
+ const_pointer operator &() const
+ {
+ return &(imultimap::data_cast(p_node)->value);
+ }
+
+ pointer operator ->()
+ {
+ return &(imultimap::data_cast(p_node)->value);
+ }
+
+ const_pointer operator ->() const
+ {
+ return &(imultimap::data_cast(p_node)->value);
+ }
+
+ friend bool operator == (const iterator& lhs, const iterator& rhs)
+ {
+ return lhs.p_multimap == rhs.p_multimap && lhs.p_node == rhs.p_node;
+ }
+
+ friend bool operator != (const iterator& lhs, const iterator& rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+ private:
+
+ // Pointer to multimap associated with this iterator
+ imultimap* p_multimap;
+
+ // Pointer to the current node for this iterator
+ Node* p_node;
+ };
+ friend class iterator;
+
+ //*************************************************************************
+ /// const_iterator
+ //*************************************************************************
+ class const_iterator : public std::iterator<std::bidirectional_iterator_tag, const value_type>
+ {
+ public:
+
+ friend class imultimap;
+
+ const_iterator()
+ : p_multimap(nullptr)
+ , p_node(nullptr)
+ {
+ }
+
+ const_iterator(const imultimap& multimap)
+ : p_multimap(&multimap)
+ , p_node(nullptr)
+ {
+ }
+
+ const_iterator(const imultimap& multimap, const Node* node)
+ : p_multimap(&multimap)
+ , p_node(node)
+ {
+ }
+
+ const_iterator(const typename imultimap::iterator& other)
+ : p_multimap(other.p_multimap)
+ , p_node(other.p_node)
+ {
+ }
+
+ const_iterator(const const_iterator& other)
+ : p_multimap(other.p_multimap)
+ , p_node(other.p_node)
+ {
+ }
+
+ ~const_iterator()
+ {
+ }
+
+ const_iterator& operator ++()
+ {
+ p_multimap->next_node(p_node);
+ return *this;
+ }
+
+ const_iterator operator ++(int)
+ {
+ const_iterator temp(*this);
+ p_multimap->next_node(p_node);
+ return temp;
+ }
+
+ const_iterator& operator --()
+ {
+ p_multimap->prev_node(p_node);
+ return *this;
+ }
+
+ const_iterator operator --(int)
+ {
+ const_iterator temp(*this);
+ p_multimap->prev_node(p_node);
+ return temp;
+ }
+
+ const_iterator operator =(const const_iterator& other)
+ {
+ p_multimap = other.p_multimap;
+ p_node = other.p_node;
+ return *this;
+ }
+
+ const_reference operator *() const
+ {
+ return imultimap::data_cast(p_node)->value;
+ }
+
+ const_pointer operator &() const
+ {
+ return imultimap::data_cast(p_node)->value;
+ }
+
+ const_pointer operator ->() const
+ {
+ return &(imultimap::data_cast(p_node)->value);
+ }
+
+ friend bool operator == (const const_iterator& lhs, const const_iterator& rhs)
+ {
+ return lhs.p_multimap == rhs.p_multimap && lhs.p_node == rhs.p_node;
+ }
+
+ friend bool operator != (const const_iterator& lhs, const const_iterator& rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+ private:
+ // Pointer to multimap associated with this iterator
+ const imultimap* p_multimap;
+
+ // Pointer to the current node for this iterator
+ const Node* p_node;
+ };
+ friend class const_iterator;
+
+ typedef typename std::iterator_traits<iterator>::difference_type difference_type;
+
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+
+
+ //*************************************************************************
+ /// Gets the beginning of the multimap.
+ //*************************************************************************
+ iterator begin()
+ {
+ return iterator(*this, find_limit_node(root_node, kLeft));
+ }
+
+ //*************************************************************************
+ /// Gets the beginning of the multimap.
+ //*************************************************************************
+ const_iterator begin() const
+ {
+ return const_iterator(*this, find_limit_node(root_node, kLeft));
+ }
+
+ //*************************************************************************
+ /// Gets the end of the multimap.
+ //*************************************************************************
+ iterator end()
+ {
+ return iterator(*this);
+ }
+
+ //*************************************************************************
+ /// Gets the end of the multimap.
+ //*************************************************************************
+ const_iterator end() const
+ {
+ return const_iterator(*this);
+ }
+
+ //*************************************************************************
+ /// Gets the beginning of the multimap.
+ //*************************************************************************
+ const_iterator cbegin() const
+ {
+ return const_iterator(*this, find_limit_node(root_node, kLeft));
+ }
+
+ //*************************************************************************
+ /// Gets the end of the multimap.
+ //*************************************************************************
+ const_iterator cend() const
+ {
+ return const_iterator(*this);
+ }
+
+ //*************************************************************************
+ /// Gets the reverse beginning of the list.
+ //*************************************************************************
+ reverse_iterator rbegin()
+ {
+ return reverse_iterator(iterator(*this));
+ }
+
+ //*************************************************************************
+ /// Gets the reverse beginning of the list.
+ //*************************************************************************
+ const_reverse_iterator rbegin() const
+ {
+ return const_reverse_iterator(const_iterator(*this));
+ }
+
+ //*************************************************************************
+ /// Gets the reverse end of the list.
+ //*************************************************************************
+ reverse_iterator rend()
+ {
+ return reverse_iterator(iterator(*this, find_limit_node(root_node, kLeft)));
+ }
+
+ //*************************************************************************
+ /// Gets the reverse end of the list.
+ //*************************************************************************
+ const_reverse_iterator rend() const
+ {
+ return const_reverse_iterator(iterator(*this, find_limit_node(root_node, kLeft)));
+ }
+
+ //*************************************************************************
+ /// Gets the reverse beginning of the list.
+ //*************************************************************************
+ const_reverse_iterator crbegin() const
+ {
+ return const_reverse_iterator(const_iterator(*this));
+ }
+
+ //*************************************************************************
+ /// Gets the reverse end of the list.
+ //*************************************************************************
+ const_reverse_iterator crend() const
+ {
+ return const_reverse_iterator(const_iterator(*this, find_limit_node(root_node, kLeft)));
+ }
+
+ //*********************************************************************
+ /// Assigns values to the multimap.
+ /// If asserts or exceptions are enabled, emits map_full if the multimap does not have enough free space.
+ /// If asserts or exceptions are enabled, emits map_iterator if the iterators are reversed.
+ ///\param first The iterator to the first element.
+ ///\param last The iterator to the last element + 1.
+ //*********************************************************************
+ template <typename TIterator>
+ void assign(TIterator first, TIterator last)
+ {
+ initialise();
+ insert(first, last);
+ }
+
+ //*************************************************************************
+ /// Clears the multimap.
+ //*************************************************************************
+ void clear()
+ {
+ initialise();
+ }
+
+ //*********************************************************************
+ /// Counts the number of elements that contain the key specified.
+ ///\param key The key to search for.
+ ///\return 1 if element was found, 0 otherwise.
+ //*********************************************************************
+ size_type count(const key_value_parameter_t& key) const
+ {
+ return count_nodes(key);
+ }
+
+ //*************************************************************************
+ /// Returns two iterators with bounding (lower bound, upper bound) the key
+ /// provided
+ //*************************************************************************
+ std::pair<iterator, iterator> equal_range(const key_value_parameter_t& key)
+ {
+ return std::make_pair<iterator, iterator>(
+ iterator(*this, find_lower_node(root_node, key)),
+ iterator(*this, find_upper_node(root_node, key)));
+ }
+
+ //*************************************************************************
+ /// Returns two const iterators with bounding (lower bound, upper bound)
+ /// the key provided.
+ //*************************************************************************
+ std::pair<const_iterator, const_iterator> equal_range(const key_value_parameter_t& key) const
+ {
+ return std::make_pair<const_iterator, const_iterator>(
+ const_iterator(*this, find_lower_node(root_node, key)),
+ const_iterator(*this, find_upper_node(root_node, key)));
+ }
+
+ //*************************************************************************
+ /// Erases the value at the specified position.
+ //*************************************************************************
+ void erase(iterator position)
+ {
+ // Remove the node by its node specified in iterator position
+ (void)erase(const_iterator(position));
+ }
+
+ //*************************************************************************
+ /// Erases the value at the specified position.
+ //*************************************************************************
+ iterator erase(const_iterator position)
+ {
+ // Cast const away from node to be removed. This is necessary because the
+ // STL definition of this method requires we provide the next node in the
+ // sequence as an iterator.
+ Node* node = const_cast<Node*>(position.p_node);
+ iterator next(*this, node);
+ ++next;
+
+ // Remove the non-const node provided
+ remove_node(node);
+
+ return next;
+ }
+
+ //*************************************************************************
+ // Erase the key specified.
+ //*************************************************************************
+ size_type erase(const key_value_parameter_t& key)
+ {
+ // Number of nodes removed
+ size_type count = 0;
+ const_iterator lower(*this, find_lower_node(root_node, key));
+ const_iterator upper(*this, find_upper_node(root_node, key));
+ while (lower != upper)
+ {
+ // Increment count for each node removed
+ ++count;
+ // Remove node using the other erase method
+ (void)erase(lower++);
+ }
+
+ // Return the total count erased
+ return count;
+ }
+
+ //*************************************************************************
+ /// Erases a range of elements.
+ //*************************************************************************
+ iterator erase(iterator first, iterator last)
+ {
+ iterator next;
+ while (first != last)
+ {
+ next = erase(const_iterator(first++));
+ }
+
+ return next;
+ }
+
+ //*************************************************************************
+ /// Erases a range of elements.
+ //*************************************************************************
+ iterator erase(const_iterator first, const_iterator last)
+ {
+ iterator next;
+ while (first != last)
+ {
+ next = erase(first++);
+ }
+
+ return next;
+ }
+
+ //*********************************************************************
+ /// Finds an element.
+ ///\param key The key to search for.
+ ///\return An iterator pointing to the element or end() if not found.
+ //*********************************************************************
+ iterator find(const key_value_parameter_t& key)
+ {
+ return iterator(*this, find_node(root_node, key));
+ }
+
+ //*********************************************************************
+ /// Finds an element.
+ ///\param key The key to search for.
+ ///\return An iterator pointing to the element or end() if not found.
+ //*********************************************************************
+ const_iterator find(const key_value_parameter_t& key) const
+ {
+ return const_iterator(*this, find_node(root_node, key));
+ }
+
+ //*********************************************************************
+ /// Inserts a value to the multimap.
+ /// If asserts or exceptions are enabled, emits map_full if the multimap is already full.
+ ///\param value The value to insert.
+ //*********************************************************************
+ iterator insert(const value_type& value)
+ {
+ // Default to no inserted node
+ Node* inserted_node = nullptr;
+
+ ETL_ASSERT(!full(), ETL_ERROR(multimap_full));
+
+ // Get next available free node
+ Data_Node& node = allocate_data_node(value);
+
+ // Obtain the inserted node (might be nullptr if node was a duplicate)
+ inserted_node = insert_node(root_node, node);
+
+ // Insert node into tree and return iterator to new node location in tree
+ return iterator(*this, inserted_node);
+ }
+
+ //*********************************************************************
+ /// Inserts a value to the multimap starting at the position recommended.
+ /// If asserts or exceptions are enabled, emits map_full if the multimap is already full.
+ ///\param position The position that would precede the value to insert.
+ ///\param value The value to insert.
+ //*********************************************************************
+ iterator insert(iterator position, const value_type& value)
+ {
+ // Ignore position provided and just do a normal insert
+ return insert(value);
+ }
+
+ //*********************************************************************
+ /// Inserts a value to the multimap starting at the position recommended.
+ /// If asserts or exceptions are enabled, emits map_full if the multimap is already full.
+ ///\param position The position that would precede the value to insert.
+ ///\param value The value to insert.
+ //*********************************************************************
+ iterator insert(const_iterator position, const value_type& value)
+ {
+ // Ignore position provided and just do a normal insert
+ return insert(value);
+ }
+
+ //*********************************************************************
+ /// Inserts a range of values to the multimap.
+ /// If asserts or exceptions are enabled, emits map_full if the multimap does not have enough free space.
+ ///\param position The position to insert at.
+ ///\param first The first element to add.
+ ///\param last The last + 1 element to add.
+ //*********************************************************************
+ template <class TIterator>
+ void insert(TIterator first, TIterator last)
+ {
+ while (first != last)
+ {
+ insert(*first++);
+ }
+ }
+
+ //*********************************************************************
+ /// Returns an iterator pointing to the first element in the container
+ /// whose key is not considered to go before the key provided or end()
+ /// if all keys are considered to go before the key provided.
+ ///\return An iterator pointing to the element not before key or end()
+ //*********************************************************************
+ iterator lower_bound(const key_value_parameter_t& key)
+ {
+ return iterator(*this, find_lower_node(root_node, key));
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator pointing to the first element in the
+ /// container whose key is not considered to go before the key provided
+ /// or end() if all keys are considered to go before the key provided.
+ ///\return An const_iterator pointing to the element not before key or end()
+ //*********************************************************************
+ const_iterator lower_bound(const key_value_parameter_t& key) const
+ {
+ return const_iterator(*this, find_lower_node(root_node, key));
+ }
+
+ //*********************************************************************
+ /// Returns an iterator pointing to the first element in the container
+ /// whose key is not considered to go after the key provided or end()
+ /// if all keys are considered to go after the key provided.
+ ///\return An iterator pointing to the element after key or end()
+ //*********************************************************************
+ iterator upper_bound(const key_value_parameter_t& key)
+ {
+ return iterator(*this, find_upper_node(root_node, key));
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator pointing to the first element in the
+ /// container whose key is not considered to go after the key provided
+ /// or end() if all keys are considered to go after the key provided.
+ ///\return An const_iterator pointing to the element after key or end()
+ //*********************************************************************
+ const_iterator upper_bound(const key_value_parameter_t& key) const
+ {
+ return const_iterator(*this, find_upper_node(root_node, key));
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ imultimap& operator = (const imultimap& rhs)
+ {
+ // Skip if doing self assignment
+ if (this != &rhs)
+ {
+ assign(rhs.cbegin(), rhs.cend());
+ }
+
+ return *this;
+ }
+
+ protected:
+
+ //*************************************************************************
+ /// Constructor.
+ //*************************************************************************
+ imultimap(ipool<Data_Node>& node_pool, size_t max_size_)
+ : multimap_base(max_size_)
+ , p_node_pool(&node_pool)
+ {
+ }
+
+ //*************************************************************************
+ /// Initialise the multimap.
+ //*************************************************************************
+ void initialise()
+ {
+ if (!empty())
+ {
+ p_node_pool->release_all();
+ }
+
+ current_size = 0;
+ root_node = nullptr;
+ }
+
+ private:
+
+ //*************************************************************************
+ /// Allocate a Data_Node.
+ //*************************************************************************
+ Data_Node& allocate_data_node(value_type value) const
+ {
+ return *(p_node_pool->allocate(Data_Node(value)));
+ }
+
+ //*************************************************************************
+ /// Destroy a Data_Node.
+ //*************************************************************************
+ void destroy_data_node(Data_Node& node) const
+ {
+ p_node_pool->release(&node);
+ }
+
+ //*************************************************************************
+ /// Count the nodes that match the key provided
+ //*************************************************************************
+ size_type count_nodes(const key_value_parameter_t& key) const
+ {
+ // Number of nodes that match the key provided result
+ size_type result = 0;
+
+ // Find lower and upper nodes for the key provided
+ const Node* lower = find_lower_node(root_node, key);
+ const Node* upper = find_upper_node(root_node, key);
+
+ // Loop from lower node to upper node and find nodes that match
+ while (lower != upper)
+ {
+ // Downcast found to Data_Node class for comparison and other operations
+ const Data_Node& data_node = imultimap::data_cast(*lower);
+
+ if (!node_comp(key, data_node) && !node_comp(data_node, key))
+ {
+ // This node matches the key provided
+ ++result;
+ }
+
+ // Move on to the next node
+ next_node(lower);
+ }
+
+ // Return the number of nodes that match
+ return result;
+ }
+
+ //*************************************************************************
+ /// Find the value matching the node provided
+ //*************************************************************************
+ Node* find_node(Node* position, const key_value_parameter_t& key) const
+ {
+ Node* found = nullptr;
+ while (position)
+ {
+ // Downcast found to Data_Node class for comparison and other operations
+ Data_Node& data_node = imultimap::data_cast(*position);
+ // Compare the node value to the current position value
+ if (node_comp(key, data_node))
+ {
+ // Keep searching for the node on the left
+ position = position->children[kLeft];
+ }
+ else if (node_comp(data_node, key))
+ {
+ // Keep searching for the node on the right
+ position = position->children[kRight];
+ }
+ else
+ {
+ // We found one, keep looking for more on the left
+ found = position;
+ position = position->children[kLeft];
+ }
+ }
+
+ // Return the node found (might be nullptr)
+ return found;
+ }
+
+ //*************************************************************************
+ /// Find the value matching the node provided
+ //*************************************************************************
+ const Node* find_node(const Node* position, const key_value_parameter_t& key) const
+ {
+ const Node* found = nullptr;
+ while (position)
+ {
+ // Downcast found to Data_Node class for comparison and other operations
+ const Data_Node& data_node = imultimap::data_cast(*position);
+ // Compare the node value to the current position value
+ if (node_comp(key, data_node))
+ {
+ // Keep searching for the node on the left
+ position = position->children[kLeft];
+ }
+ else if (node_comp(data_node, key))
+ {
+ // Keep searching for the node on the right
+ position = position->children[kRight];
+ }
+ else
+ {
+ // We found one, keep looking for more on the left
+ found = position;
+ position = position->children[kLeft];
+ }
+ }
+
+ // Return the node found (might be nullptr)
+ return found;
+ }
+
+ //*************************************************************************
+ /// Find the node whose key is not considered to go before the key provided
+ //*************************************************************************
+ Node* find_lower_node(Node* position, const key_value_parameter_t& key) const
+ {
+ // Something at this position? keep going
+ Node* lower_node = nullptr;
+ while (position)
+ {
+ // Downcast lower node to Data_Node reference for key comparisons
+ Data_Node& data_node = imultimap::data_cast(*position);
+ // Compare the key value to the current lower node key value
+ if (node_comp(key, data_node))
+ {
+ lower_node = position;
+ if (position->children[kLeft])
+ {
+ position = position->children[kLeft];
+ }
+ else
+ {
+ // Found lowest node
+ break;
+ }
+ }
+ else if (node_comp(data_node, key))
+ {
+ position = position->children[kRight];
+ }
+ else
+ {
+ // Make note of current position, but keep looking to left for more
+ lower_node = position;
+ position = position->children[kLeft];
+ }
+ }
+
+ // Return the lower_node position found
+ return lower_node;
+ }
+
+ //*************************************************************************
+ /// Find the node whose key is considered to go after the key provided
+ //*************************************************************************
+ Node* find_upper_node(Node* position, const key_value_parameter_t& key) const
+ {
+ // Keep track of parent of last upper node
+ Node* upper_node = nullptr;
+ // Has an equal node been found? start with no
+ bool found = false;
+ while (position)
+ {
+ // Downcast position to Data_Node reference for key comparisons
+ Data_Node& data_node = imultimap::data_cast(*position);
+ // Compare the key value to the current upper node key value
+ if (node_comp(data_node, key))
+ {
+ position = position->children[kRight];
+ }
+ else if (node_comp(key, data_node))
+ {
+ upper_node = position;
+ // If a node equal to key hasn't been found go left
+ if (!found && position->children[kLeft])
+ {
+ position = position->children[kLeft];
+ }
+ else
+ {
+ break;
+ }
+ }
+ else
+ {
+ // We found an equal item, break on next bigger item
+ found = true;
+ next_node(position);
+ }
+ }
+
+ // Return the upper node position found (might be nullptr)
+ return upper_node;
+ }
+
+ //*************************************************************************
+ /// Insert a node.
+ //*************************************************************************
+ Node* insert_node(Node*& position, Data_Node& node)
+ {
+ // Find the location where the node belongs
+ Node* found = position;
+
+ // Was position provided not empty? then find where the node belongs
+ if (position)
+ {
+ // Find the critical parent node (default to nullptr)
+ Node* critical_parent_node = nullptr;
+ Node* critical_node = root_node;
+
+ while (found)
+ {
+ // Search for critical weight node (all nodes whose weight factor
+ // is set to kNeither (balanced)
+ if (kNeither != found->weight)
+ {
+ critical_node = found;
+ }
+
+ // Downcast found to Data_Node class for comparison and other operations
+ Data_Node& found_data_node = imultimap::data_cast(*found);
+
+ // Is the node provided to the left of the current position?
+ if (node_comp(node, found_data_node))
+ {
+ // Update direction taken to insert new node in parent node
+ found->dir = kLeft;
+ }
+ // Is the node provided to the right of the current position?
+ else if (node_comp(found_data_node, node))
+ {
+ // Update direction taken to insert new node in parent node
+ found->dir = kRight;
+ }
+ else
+ {
+ // Update direction taken to insert new node in parent (and
+ // duplicate) node to the right.
+ found->dir = kRight;
+ }
+
+ // Is there a child of this parent node?
+ if (found->children[found->dir])
+ {
+ // Will this node be the parent of the next critical node whose
+ // weight factor is set to kNeither (balanced)?
+ if (kNeither != found->children[found->dir]->weight)
+ {
+ critical_parent_node = found;
+ }
+
+ // Keep looking for empty spot to insert new node
+ found = found->children[found->dir];
+ }
+ else
+ {
+ // Attach node as a child of the parent node found
+ attach_node(found, found->children[found->dir], node);
+
+ // Return newly added node
+ found = found->children[found->dir];
+
+ // Exit loop
+ break;
+ }
+ }
+
+ // Was a critical node found that should be checked for balance?
+ if (critical_node)
+ {
+ if (critical_parent_node == nullptr && critical_node == root_node)
+ {
+ balance_node(root_node);
+ }
+ else if (critical_parent_node == nullptr && critical_node == position)
+ {
+ balance_node(position);
+ }
+ else
+ {
+ balance_node(critical_parent_node->children[critical_parent_node->dir]);
+ }
+ }
+ }
+ else
+ {
+ // Attach node to current position (which is assumed to be root)
+ attach_node(nullptr, position, node);
+
+ // Return newly added node at current position
+ found = position;
+ }
+
+ // Return the node found (might be nullptr)
+ return found;
+ }
+
+ //*************************************************************************
+ /// Remove the node specified from somewhere starting at the position
+ /// provided
+ //*************************************************************************
+ void remove_node(Node* node)
+ {
+ // If valid found node was provided then proceed with steps 1 through 5
+ if (node)
+ {
+ // Downcast found node provided to Data_Node class
+ Data_Node& data_node = imultimap::data_cast(*node);
+
+ // Keep track of node as found node
+ Node* found = node;
+
+ // Step 1: Mark path from node provided back to the root node using the
+ // internal temporary dir member value and using the parent pointer. This
+ // will allow us to avoid recursion in finding the node in a tree that
+ //might contain duplicate keys to be found.
+ while (node)
+ {
+ if (node->parent)
+ {
+ // Which direction does parent use to get to this node?
+ node->parent->dir =
+ node->parent->children[kLeft] == node ? kLeft : kRight;
+
+ // Make this nodes parent the next node
+ node = node->parent;
+ }
+ else
+ {
+ // Root node found - break loop
+ break;
+ }
+ }
+
+ // Step 2: Follow the path provided above until we reach the node
+ // provided and look for the balance node to start rebalancing the tree
+ // from (up to the replacement node that will be found in step 3)
+ Node* balance = root_node;
+ while (node)
+ {
+ // Did we reach the node provided originally (found) then go to step 3
+ if (node == found)
+ {
+ // Update the direction towards a replacement node at the found node
+ node->dir = node->children[kLeft] ? kLeft : kRight;
+
+ // Exit loop and proceed with step 3
+ break;
+ }
+ else
+ {
+ // If this nodes weight is kNeither or we are taking the shorter path
+ // to the next node and our sibling (on longer path) is balanced then
+ // we need to update the balance node to this node but all our
+ // ancestors will not require rebalancing
+ if ((node->weight == kNeither) ||
+ (node->weight == (1 - node->dir) &&
+ node->children[1 - node->dir]->weight == kNeither))
+ {
+ // Update balance node to this node
+ balance = node;
+ }
+
+ // Keep searching for found in the direction provided in step 1
+ node = node->children[node->dir];
+ }
+ }
+ // The value for node should not be nullptr at this point otherwise
+ // step 1 failed to provide the correct path to found. Step 5 will fail
+ // (probably subtly) if node should be nullptr at this point
+
+ // Step 3: Find the node (node should be equal to found at this point)
+ // to replace found with (might end up equal to found) while also
+ // continuing to update balance the same as in step 2 above.
+ while (node)
+ {
+ // Replacement node found if its missing a child in the replace->dir
+ // value set at the end of step 2 above
+ if (node->children[node->dir] == nullptr)
+ {
+ // Exit loop once node to replace found is determined
+ break;
+ }
+
+ // If this nodes weight is kNeither or we are taking the shorter path
+ // to the next node and our sibling (on longer path) is balanced then
+ // we need to update the balance node to this node but all our
+ // ancestors will not require rebalancing
+ if ((node->weight == kNeither) ||
+ (node->weight == (1 - node->dir) &&
+ node->children[1 - node->dir]->weight == kNeither))
+ {
+ // Update balance node to this node
+ balance = node;
+ }
+
+ // Keep searching for replacement node in the direction specified above
+ node = node->children[node->dir];
+
+ // Downcast node to Data_Node class for comparison operations
+ Data_Node& replace_data_node = imultimap::data_cast(*node);
+
+ // Compare the key provided to the replace data node key
+ if (node_comp(data_node, replace_data_node))
+ {
+ // Update the direction to the replace node
+ node->dir = kLeft;
+ }
+ else if (node_comp(replace_data_node, data_node))
+ {
+ // Update the direction to the replace node
+ node->dir = kRight;
+ }
+ else
+ {
+ // Update the direction to the replace node
+ node->dir = node->children[kLeft] ? kLeft : kRight;
+ }
+ } // while(node)
+
+ // Step 4: Update weights from balance to parent of node determined
+ // in step 3 above rotating (2 or 3 node rotations) as needed.
+ while (balance)
+ {
+ // Break when balance node reaches the parent of replacement node
+ if (balance->children[balance->dir] == nullptr)
+ {
+ break;
+ }
+
+ // If balance node is balanced already (kNeither) then just imbalance
+ // the node in the opposite direction of the node being removed
+ if (balance->weight == kNeither)
+ {
+ balance->weight = 1 - balance->dir;
+ }
+ // If balance node is imbalanced in the opposite direction of the
+ // node being removed then the node now becomes balanced
+ else if (balance->weight == balance->dir)
+ {
+ balance->weight = kNeither;
+ }
+ // Otherwise a rotation is required at this node
+ else
+ {
+ int weight = balance->children[1 - balance->dir]->weight;
+ // Perform a 3 node rotation if weight is same as balance->dir
+ if (weight == balance->dir)
+ {
+ // Is the root node being rebalanced (no parent)
+ if (balance->parent == nullptr)
+ {
+ rotate_3node(root_node, 1 - balance->dir,
+ balance->children[1 - balance->dir]->children[balance->dir]->weight);
+ }
+ else
+ {
+ rotate_3node(balance->parent->children[balance->parent->dir], 1 - balance->dir,
+ balance->children[1 - balance->dir]->children[balance->dir]->weight);
+ }
+ }
+ // Already balanced, rebalance and make it heavy in opposite
+ // direction of the node being removed
+ else if (weight == kNeither)
+ {
+ // Is the root node being rebalanced (no parent)
+ if (balance->parent == nullptr)
+ {
+ rotate_2node(root_node, 1 - balance->dir);
+ root_node->weight = balance->dir;
+ }
+ else
+ {
+ // Balance parent might change during rotate, keep local copy
+ // to old parent so its weight can be updated after the 2 node
+ // rotate is completed
+ Node* old_parent = balance->parent;
+ rotate_2node(balance->parent->children[balance->parent->dir], 1 - balance->dir);
+ old_parent->children[old_parent->dir]->weight = balance->dir;
+ }
+ // Update balance node weight in opposite direction of node removed
+ balance->weight = 1 - balance->dir;
+ }
+ // Rebalance and leave it balanced
+ else
+ {
+ // Is the root node being rebalanced (no parent)
+ if (balance->parent == nullptr)
+ {
+ rotate_2node(root_node, 1 - balance->dir);
+ }
+ else
+ {
+ rotate_2node(balance->parent->children[balance->parent->dir], 1 - balance->dir);
+ }
+ }
+ }
+
+ // Next balance node to consider
+ balance = balance->children[balance->dir];
+ } // while(balance)
+
+ // Step 5: Swap found with node (replacement)
+ if (found->parent)
+ {
+ // Handle traditional case
+ detach_node(found->parent->children[found->parent->dir],
+ node->parent->children[node->parent->dir]);
+ }
+ // Handle root node removal
+ else
+ {
+ // Valid replacement node for root node being removed?
+ if (node->parent)
+ {
+ detach_node(root_node, node->parent->children[node->parent->dir]);
+ }
+ else
+ {
+ // Found node and replacement node are both root node
+ detach_node(root_node, root_node);
+ }
+ }
+
+ // One less.
+ --current_size;
+
+ // Destroy the node detached above
+ destroy_data_node(data_node);
+ } // if(found)
+ }
+
+ // Disable copy construction.
+ imultimap(const imultimap&);
+ };
+}
+
+//***************************************************************************
+/// Equal operator.
+///\param lhs Reference to the first lookup.
+///\param rhs Reference to the second lookup.
+///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
+///\ingroup lookup
+//***************************************************************************
+template <typename TKey, typename TMapped, typename TKeyCompare>
+bool operator ==(const etl::imultimap<TKey, TMapped, TKeyCompare>& lhs, const etl::imultimap<TKey, TMapped, TKeyCompare>& rhs)
+{
+ return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin());
+}
+
+//***************************************************************************
+/// Not equal operator.
+///\param lhs Reference to the first lookup.
+///\param rhs Reference to the second lookup.
+///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
+///\ingroup lookup
+//***************************************************************************
+template <typename TKey, typename TMapped, typename TKeyCompare>
+bool operator !=(const etl::imultimap<TKey, TMapped, TKeyCompare>& lhs, const etl::imultimap<TKey, TMapped, TKeyCompare>& rhs)
+{
+ return !(lhs == rhs);
+}
+
+//*************************************************************************
+/// Less than operator.
+///\param lhs Reference to the first list.
+///\param rhs Reference to the second list.
+///\return <b>true</b> if the first list is lexicographically less than the
+/// second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename TKey, typename TMapped, typename TKeyCompare>
+bool operator <(const etl::imultimap<TKey, TMapped, TKeyCompare>& lhs, const etl::imultimap<TKey, TMapped, TKeyCompare>& rhs)
+{
+ return std::lexicographical_compare(lhs.begin(),
+ lhs.end(),
+ rhs.begin(),
+ rhs.end());
+}
+
+//*************************************************************************
+/// Greater than operator.
+///\param lhs Reference to the first list.
+///\param rhs Reference to the second list.
+///\return <b>true</b> if the first list is lexicographically greater than the
+/// second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename TKey, typename TMapped, typename TKeyCompare>
+bool operator >(const etl::imultimap<TKey, TMapped, TKeyCompare>& lhs, const etl::imultimap<TKey, TMapped, TKeyCompare>& rhs)
+{
+ return (rhs < lhs);
+}
+
+//*************************************************************************
+/// Less than or equal operator.
+///\param lhs Reference to the first list.
+///\param rhs Reference to the second list.
+///\return <b>true</b> if the first list is lexicographically less than or equal
+/// to the second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename TKey, typename TMapped, typename TKeyCompare>
+bool operator <=(const etl::imultimap<TKey, TMapped, TKeyCompare>& lhs, const etl::imultimap<TKey, TMapped, TKeyCompare>& rhs)
+{
+ return !(lhs > rhs);
+}
+
+//*************************************************************************
+/// Greater than or equal operator.
+///\param lhs Reference to the first list.
+///\param rhs Reference to the second list.
+///\return <b>true</b> if the first list is lexicographically greater than or
+/// equal to the second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename TKey, typename TMapped, typename TKeyCompare>
+bool operator >=(const etl::imultimap<TKey, TMapped, TKeyCompare>& lhs, const etl::imultimap<TKey, TMapped, TKeyCompare>& rhs)
+{
+ return !(lhs < rhs);
+}
+
+#ifdef ETL_COMPILER_MICROSOFT
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#undef __ETL_IN_IMULTIMAP_H__
+
+#endif
diff --git a/lib/etl/imultiset.h b/lib/etl/imultiset.h
new file mode 100644
index 0000000..9f36182
--- /dev/null
+++ b/lib/etl/imultiset.h
@@ -0,0 +1,1405 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove, rlindeman
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_IMULTISET__
+#define __ETL_IMULTISET__
+#define __ETL_IN_IMULTISET_H__
+
+#include <iterator>
+#include <algorithm>
+#include <functional>
+#include <stddef.h>
+
+#include "nullptr.h"
+#include "private/multiset_base.h"
+#include "type_traits.h"
+#include "parameter_type.h"
+#include "pool.h"
+#include "platform.h"
+
+#ifdef ETL_COMPILER_MICROSOFT
+#undef min
+#endif
+
+namespace etl
+{
+ //***************************************************************************
+ /// A templated base for all etl::multiset types.
+ ///\ingroup set
+ //***************************************************************************
+ template <typename T, typename TCompare>
+ class imultiset : public multiset_base
+ {
+ public:
+
+ typedef const T key_type;
+ typedef const T value_type;
+ typedef TCompare key_compare;
+ typedef TCompare value_compare;
+ typedef value_type& const_reference;
+ typedef value_type* const_pointer;
+ typedef size_t size_type;
+
+ //*************************************************************************
+ /// How to compare two key elements.
+ //*************************************************************************
+ struct key_comp
+ {
+ bool operator ()(key_type& key1, key_type& key2) const
+ {
+ return key_compare()(key1, key2);
+ }
+ };
+
+ //*************************************************************************
+ /// How to compare two value elements.
+ //*************************************************************************
+ struct value_comp
+ {
+ bool operator ()(value_type& value1, value_type& value2) const
+ {
+ return value_compare()(value1, value2);
+ }
+ };
+
+ protected:
+
+ //*************************************************************************
+ /// The data node element in the multiset.
+ //*************************************************************************
+ struct Data_Node : public Node
+ {
+ explicit Data_Node(value_type value)
+ : value(value)
+ {
+ }
+
+ value_type value;
+ };
+
+ /// Defines the key value parameter type
+ typedef typename parameter_type<T>::type key_value_parameter_t;
+
+ //*************************************************************************
+ /// How to compare node elements.
+ //*************************************************************************
+ bool node_comp(const Data_Node& node1, const Data_Node& node2) const
+ {
+ return key_compare()(node1.value, node2.value);
+ }
+ bool node_comp(const Data_Node& node, const key_value_parameter_t& key) const
+ {
+ return key_compare()(node.value, key);
+ }
+ bool node_comp(const key_value_parameter_t& key, const Data_Node& node) const
+ {
+ return key_compare()(key, node.value);
+ }
+
+ private:
+
+ /// The pool of data nodes used in the multiset.
+ ipool<Data_Node>* p_node_pool;
+
+ //*************************************************************************
+ /// Downcast a Node* to a Data_Node*
+ //*************************************************************************
+ static Data_Node* data_cast(Node* p_node)
+ {
+ return static_cast<Data_Node*>(p_node);
+ }
+
+ //*************************************************************************
+ /// Downcast a Node& to a Data_Node&
+ //*************************************************************************
+ static Data_Node& data_cast(Node& node)
+ {
+ return static_cast<Data_Node&>(node);
+ }
+
+ //*************************************************************************
+ /// Downcast a const Node* to a const Data_Node*
+ //*************************************************************************
+ static const Data_Node* data_cast(const Node* p_node)
+ {
+ return static_cast<const Data_Node*>(p_node);
+ }
+
+ //*************************************************************************
+ /// Downcast a const Node& to a const Data_Node&
+ //*************************************************************************
+ static const Data_Node& data_cast(const Node& node)
+ {
+ return static_cast<const Data_Node&>(node);
+ }
+
+ public:
+ //*************************************************************************
+ /// iterator.
+ //*************************************************************************
+ class iterator : public std::iterator<std::bidirectional_iterator_tag, value_type>
+ {
+ public:
+
+ friend class imultiset;
+
+ iterator()
+ : p_multiset(nullptr)
+ , p_node(nullptr)
+ {
+ }
+
+ iterator(imultiset& multiset)
+ : p_multiset(&multiset)
+ , p_node(nullptr)
+ {
+ }
+
+ iterator(imultiset& multiset, Node* node)
+ : p_multiset(&multiset)
+ , p_node(node)
+ {
+ }
+
+ iterator(const iterator& other)
+ : p_multiset(other.p_multiset)
+ , p_node(other.p_node)
+ {
+ }
+
+ ~iterator()
+ {
+ }
+
+ iterator& operator ++()
+ {
+ p_multiset->next_node(p_node);
+ return *this;
+ }
+
+ iterator operator ++(int)
+ {
+ iterator temp(*this);
+ p_multiset->next_node(p_node);
+ return temp;
+ }
+
+ iterator& operator --()
+ {
+ p_multiset->prev_node(p_node);
+ return *this;
+ }
+
+ iterator operator --(int)
+ {
+ iterator temp(*this);
+ p_multiset->prev_node(p_node);
+ return temp;
+ }
+
+ iterator operator =(const iterator& other)
+ {
+ p_multiset = other.p_multiset;
+ p_node = other.p_node;
+ return *this;
+ }
+
+ const_reference operator *() const
+ {
+ return imultiset::data_cast(p_node)->value;
+ }
+
+ const_pointer operator &() const
+ {
+ return &(imultiset::data_cast(p_node)->value);
+ }
+
+ const_pointer operator ->() const
+ {
+ return &(imultiset::data_cast(p_node)->value);
+ }
+
+ friend bool operator == (const iterator& lhs, const iterator& rhs)
+ {
+ return lhs.p_multiset == rhs.p_multiset && lhs.p_node == rhs.p_node;
+ }
+
+ friend bool operator != (const iterator& lhs, const iterator& rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+ private:
+
+ // Pointer to multiset associated with this iterator
+ imultiset* p_multiset;
+
+ // Pointer to the current node for this iterator
+ Node* p_node;
+ };
+ friend class iterator;
+
+ //*************************************************************************
+ /// const_iterator
+ //*************************************************************************
+ class const_iterator : public std::iterator<std::bidirectional_iterator_tag, const value_type>
+ {
+ public:
+
+ friend class imultiset;
+
+ const_iterator()
+ : p_multiset(nullptr)
+ , p_node(nullptr)
+ {
+ }
+
+ const_iterator(const imultiset& multiset)
+ : p_multiset(&multiset)
+ , p_node(nullptr)
+ {
+ }
+
+ const_iterator(const imultiset& multiset, const Node* node)
+ : p_multiset(&multiset)
+ , p_node(node)
+ {
+ }
+
+ const_iterator(const typename imultiset::iterator& other)
+ : p_multiset(other.p_multiset)
+ , p_node(other.p_node)
+ {
+ }
+
+ const_iterator(const const_iterator& other)
+ : p_multiset(other.p_multiset)
+ , p_node(other.p_node)
+ {
+ }
+
+ ~const_iterator()
+ {
+ }
+
+ const_iterator& operator ++()
+ {
+ p_multiset->next_node(p_node);
+ return *this;
+ }
+
+ const_iterator operator ++(int)
+ {
+ const_iterator temp(*this);
+ p_multiset->next_node(p_node);
+ return temp;
+ }
+
+ const_iterator& operator --()
+ {
+ p_multiset->prev_node(p_node);
+ return *this;
+ }
+
+ const_iterator operator --(int)
+ {
+ const_iterator temp(*this);
+ p_multiset->prev_node(p_node);
+ return temp;
+ }
+
+ const_iterator operator =(const const_iterator& other)
+ {
+ p_multiset = other.p_multiset;
+ p_node = other.p_node;
+ return *this;
+ }
+
+ const_reference operator *() const
+ {
+ return imultiset::data_cast(p_node)->value;
+ }
+
+ const_pointer operator &() const
+ {
+ return imultiset::data_cast(p_node)->value;
+ }
+
+ const_pointer operator ->() const
+ {
+ return &(imultiset::data_cast(p_node)->value);
+ }
+
+ friend bool operator == (const const_iterator& lhs, const const_iterator& rhs)
+ {
+ return lhs.p_multiset == rhs.p_multiset && lhs.p_node == rhs.p_node;
+ }
+
+ friend bool operator != (const const_iterator& lhs, const const_iterator& rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+ private:
+ // Pointer to multiset associated with this iterator
+ const imultiset* p_multiset;
+
+ // Pointer to the current node for this iterator
+ const Node* p_node;
+ };
+ friend class const_iterator;
+
+ typedef typename std::iterator_traits<iterator>::difference_type difference_type;
+
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+
+
+ //*************************************************************************
+ /// Gets the beginning of the multiset.
+ //*************************************************************************
+ iterator begin()
+ {
+ return iterator(*this, find_limit_node(root_node, kLeft));
+ }
+
+ //*************************************************************************
+ /// Gets the beginning of the multiset.
+ //*************************************************************************
+ const_iterator begin() const
+ {
+ return const_iterator(*this, find_limit_node(root_node, kLeft));
+ }
+
+ //*************************************************************************
+ /// Gets the end of the multiset.
+ //*************************************************************************
+ iterator end()
+ {
+ return iterator(*this);
+ }
+
+ //*************************************************************************
+ /// Gets the end of the multiset.
+ //*************************************************************************
+ const_iterator end() const
+ {
+ return const_iterator(*this);
+ }
+
+ //*************************************************************************
+ /// Gets the beginning of the multiset.
+ //*************************************************************************
+ const_iterator cbegin() const
+ {
+ return const_iterator(*this, find_limit_node(root_node, kLeft));
+ }
+
+ //*************************************************************************
+ /// Gets the end of the multiset.
+ //*************************************************************************
+ const_iterator cend() const
+ {
+ return const_iterator(*this);
+ }
+
+ //*************************************************************************
+ /// Gets the reverse beginning of the list.
+ //*************************************************************************
+ reverse_iterator rbegin()
+ {
+ return reverse_iterator(iterator(*this));
+ }
+
+ //*************************************************************************
+ /// Gets the reverse beginning of the list.
+ //*************************************************************************
+ const_reverse_iterator rbegin() const
+ {
+ return const_reverse_iterator(const_iterator(*this));
+ }
+
+ //*************************************************************************
+ /// Gets the reverse end of the list.
+ //*************************************************************************
+ reverse_iterator rend()
+ {
+ return reverse_iterator(iterator(*this, find_limit_node(root_node, kLeft)));
+ }
+
+ //*************************************************************************
+ /// Gets the reverse end of the list.
+ //*************************************************************************
+ const_reverse_iterator rend() const
+ {
+ return const_reverse_iterator(iterator(*this, find_limit_node(root_node, kLeft)));
+ }
+
+ //*************************************************************************
+ /// Gets the reverse beginning of the list.
+ //*************************************************************************
+ const_reverse_iterator crbegin() const
+ {
+ return const_reverse_iterator(const_iterator(*this));
+ }
+
+ //*************************************************************************
+ /// Gets the reverse end of the list.
+ //*************************************************************************
+ const_reverse_iterator crend() const
+ {
+ return const_reverse_iterator(const_iterator(*this, find_limit_node(root_node, kLeft)));
+ }
+
+ //*********************************************************************
+ /// Assigns values to the multiset.
+ /// If asserts or exceptions are enabled, emits set_full if the multiset does not have enough free space.
+ /// If asserts or exceptions are enabled, emits set_iterator if the iterators are reversed.
+ ///\param first The iterator to the first element.
+ ///\param last The iterator to the last element + 1.
+ //*********************************************************************
+ template <typename TIterator>
+ void assign(TIterator first, TIterator last)
+ {
+ initialise();
+ insert(first, last);
+ }
+
+ //*************************************************************************
+ /// Clears the multiset.
+ //*************************************************************************
+ void clear()
+ {
+ initialise();
+ }
+
+ //*********************************************************************
+ /// Counts the number of elements that contain the key specified.
+ ///\param key The key to search for.
+ ///\return 1 if element was found, 0 otherwise.
+ //*********************************************************************
+ size_type count(const key_value_parameter_t& key) const
+ {
+ return count_nodes(key);
+ }
+
+ //*************************************************************************
+ /// Returns two iterators with bounding (lower bound, upper bound) the key
+ /// provided
+ //*************************************************************************
+ std::pair<iterator, iterator> equal_range(const value_type& key)
+ {
+ return std::make_pair<iterator, iterator>(
+ iterator(*this, find_lower_node(root_node, key)),
+ iterator(*this, find_upper_node(root_node, key)));
+ }
+
+ //*************************************************************************
+ /// Returns two const iterators with bounding (lower bound, upper bound)
+ /// the key provided.
+ //*************************************************************************
+ std::pair<const_iterator, const_iterator> equal_range(const value_type& key) const
+ {
+ return std::make_pair<const_iterator, const_iterator>(
+ const_iterator(*this, find_lower_node(root_node, key)),
+ const_iterator(*this, find_upper_node(root_node, key)));
+ }
+
+ //*************************************************************************
+ /// Erases the value at the specified position.
+ //*************************************************************************
+ void erase(iterator position)
+ {
+ // Remove the node by its node specified in iterator position
+ (void)erase(const_iterator(position));
+ }
+
+ //*************************************************************************
+ /// Erases the value at the specified position.
+ //*************************************************************************
+ iterator erase(const_iterator position)
+ {
+ // Cast const away from node to be removed. This is necessary because the
+ // STL definition of this method requires we provide the next node in the
+ // sequence as an iterator.
+ Node* node = const_cast<Node*>(position.p_node);
+ iterator next(*this, node);
+ ++next;
+
+ // Remove the non-const node provided
+ remove_node(node);
+
+ return next;
+ }
+
+ //*************************************************************************
+ // Erase the key specified.
+ //*************************************************************************
+ size_type erase(const key_value_parameter_t& key_value)
+ {
+ // Number of nodes removed
+ size_type count = 0;
+ const_iterator lower(*this, find_lower_node(root_node, key_value));
+ const_iterator upper(*this, find_upper_node(root_node, key_value));
+ while (lower != upper)
+ {
+ // Increment count for each node removed
+ ++count;
+ // Remove node using the other erase method
+ (void)erase(lower++);
+ }
+
+ // Return the total count erased
+ return count;
+ }
+
+ //*************************************************************************
+ /// Erases a range of elements.
+ //*************************************************************************
+ iterator erase(iterator first, iterator last)
+ {
+ iterator next;
+ while (first != last)
+ {
+ next = erase(const_iterator(first++));
+ }
+
+ return next;
+ }
+
+ //*************************************************************************
+ /// Erases a range of elements.
+ //*************************************************************************
+ iterator erase(const_iterator first, const_iterator last)
+ {
+ iterator next;
+ while (first != last)
+ {
+ next = erase(first++);
+ }
+
+ return next;
+ }
+
+ //*********************************************************************
+ /// Finds an element.
+ ///\param key The key to search for.
+ ///\return An iterator pointing to the element or end() if not found.
+ //*********************************************************************
+ iterator find(const key_value_parameter_t& key_value)
+ {
+ return iterator(*this, find_node(root_node, key_value));
+ }
+
+ //*********************************************************************
+ /// Finds an element.
+ ///\param key The key to search for.
+ ///\return An iterator pointing to the element or end() if not found.
+ //*********************************************************************
+ const_iterator find(const key_value_parameter_t& key_value) const
+ {
+ return const_iterator(*this, find_node(root_node, key_value));
+ }
+
+ //*********************************************************************
+ /// Inserts a value to the multiset.
+ /// If asserts or exceptions are enabled, emits set_full if the multiset is already full.
+ ///\param value The value to insert.
+ //*********************************************************************
+ iterator insert(const value_type& value)
+ {
+ // Default to no inserted node
+ Node* inserted_node = nullptr;
+
+ ETL_ASSERT(!full(), ETL_ERROR(multiset_full));
+
+ // Get next available free node
+ Data_Node& node = allocate_data_node(value);
+
+ // Obtain the inserted node (might be nullptr if node was a duplicate)
+ inserted_node = insert_node(root_node, node);
+
+ // Insert node into tree and return iterator to new node location in tree
+ return iterator(*this, inserted_node);
+ }
+
+ //*********************************************************************
+ /// Inserts a value to the multiset starting at the position recommended.
+ /// If asserts or exceptions are enabled, emits set_full if the multiset is already full.
+ ///\param position The position that would precede the value to insert.
+ ///\param value The value to insert.
+ //*********************************************************************
+ iterator insert(iterator position, const value_type& value)
+ {
+ // Ignore position provided and just do a normal insert
+ return insert(value);
+ }
+
+ //*********************************************************************
+ /// Inserts a value to the multiset starting at the position recommended.
+ /// If asserts or exceptions are enabled, emits set_full if the multiset is already full.
+ ///\param position The position that would precede the value to insert.
+ ///\param value The value to insert.
+ //*********************************************************************
+ iterator insert(const_iterator position, const value_type& value)
+ {
+ // Ignore position provided and just do a normal insert
+ return insert(value);
+ }
+
+ //*********************************************************************
+ /// Inserts a range of values to the multiset.
+ /// If asserts or exceptions are enabled, emits set_full if the multiset does not have enough free space.
+ ///\param position The position to insert at.
+ ///\param first The first element to add.
+ ///\param last The last + 1 element to add.
+ //*********************************************************************
+ template <class TIterator>
+ void insert(TIterator first, TIterator last)
+ {
+ while (first != last)
+ {
+ insert(*first++);
+ }
+ }
+
+ //*********************************************************************
+ /// Returns an iterator pointing to the first element in the container
+ /// whose key is not considered to go before the key provided or end()
+ /// if all keys are considered to go before the key provided.
+ ///\return An iterator pointing to the element not before key or end()
+ //*********************************************************************
+ iterator lower_bound(const key_value_parameter_t& key)
+ {
+ return iterator(*this, find_lower_node(root_node, key));
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator pointing to the first element in the
+ /// container whose key is not considered to go before the key provided
+ /// or end() if all keys are considered to go before the key provided.
+ ///\return An const_iterator pointing to the element not before key or end()
+ //*********************************************************************
+ const_iterator lower_bound(const key_value_parameter_t& key) const
+ {
+ return const_iterator(*this, find_lower_node(root_node, key));
+ }
+
+ //*********************************************************************
+ /// Returns an iterator pointing to the first element in the container
+ /// whose key is not considered to go after the key provided or end()
+ /// if all keys are considered to go after the key provided.
+ ///\return An iterator pointing to the element after key or end()
+ //*********************************************************************
+ iterator upper_bound(const key_value_parameter_t& key)
+ {
+ return iterator(*this, find_upper_node(root_node, key));
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator pointing to the first element in the
+ /// container whose key is not considered to go after the key provided
+ /// or end() if all keys are considered to go after the key provided.
+ ///\return An const_iterator pointing to the element after key or end()
+ //*********************************************************************
+ const_iterator upper_bound(const key_value_parameter_t& key) const
+ {
+ return const_iterator(*this, find_upper_node(root_node, key));
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ imultiset& operator = (const imultiset& rhs)
+ {
+ // Skip if doing self assignment
+ if (this != &rhs)
+ {
+ assign(rhs.cbegin(), rhs.cend());
+ }
+
+ return *this;
+ }
+
+ protected:
+
+ //*************************************************************************
+ /// Constructor.
+ //*************************************************************************
+ imultiset(ipool<Data_Node>& node_pool, size_t max_size_)
+ : multiset_base(max_size_)
+ , p_node_pool(&node_pool)
+ {
+ }
+
+ //*************************************************************************
+ /// Initialise the multiset.
+ //*************************************************************************
+ void initialise()
+ {
+ if (!empty())
+ {
+ p_node_pool->release_all();
+ }
+
+ current_size = 0;
+ root_node = nullptr;
+ }
+
+ private:
+
+ //*************************************************************************
+ /// Allocate a Data_Node.
+ //*************************************************************************
+ Data_Node& allocate_data_node(value_type value) const
+ {
+ return *(p_node_pool->allocate(Data_Node(value)));
+ }
+
+ //*************************************************************************
+ /// Destroy a Data_Node.
+ //*************************************************************************
+ void destroy_data_node(Data_Node& node) const
+ {
+ p_node_pool->release(&node);
+ }
+
+ //*************************************************************************
+ /// Count the nodes that match the key provided
+ //*************************************************************************
+ size_type count_nodes(const key_value_parameter_t& key) const
+ {
+ // Number of nodes that match the key provided result
+ size_type result = 0;
+
+ // Find lower and upper nodes for the key provided
+ const Node* lower = find_lower_node(root_node, key);
+ const Node* upper = find_upper_node(root_node, key);
+
+ // Loop from lower node to upper node and find nodes that match
+ while (lower != upper)
+ {
+ // Downcast found to Data_Node class for comparison and other operations
+ const Data_Node& data_node = imultiset::data_cast(*lower);
+
+ if (!node_comp(key, data_node) && !node_comp(data_node, key))
+ {
+ // This node matches the key provided
+ ++result;
+ }
+
+ // Move on to the next node
+ next_node(lower);
+ }
+
+ // Return the number of nodes that match
+ return result;
+ }
+
+ //*************************************************************************
+ /// Find the value matching the node provided
+ //*************************************************************************
+ Node* find_node(Node* position, const key_value_parameter_t& key) const
+ {
+ Node* found = nullptr;
+ while (position)
+ {
+ // Downcast found to Data_Node class for comparison and other operations
+ Data_Node& data_node = imultiset::data_cast(*position);
+ // Compare the node value to the current position value
+ if (node_comp(key, data_node))
+ {
+ // Keep searching for the node on the left
+ position = position->children[kLeft];
+ }
+ else if (node_comp(data_node, key))
+ {
+ // Keep searching for the node on the right
+ position = position->children[kRight];
+ }
+ else
+ {
+ // We found one, keep looking for more on the left
+ found = position;
+ position = position->children[kLeft];
+ }
+ }
+
+ // Return the node found (might be nullptr)
+ return found;
+ }
+
+ //*************************************************************************
+ /// Find the value matching the node provided
+ //*************************************************************************
+ const Node* find_node(const Node* position, const key_value_parameter_t& key) const
+ {
+ const Node* found = nullptr;
+ while (position)
+ {
+ // Downcast found to Data_Node class for comparison and other operations
+ const Data_Node& data_node = imultiset::data_cast(*position);
+ // Compare the node value to the current position value
+ if (node_comp(key, data_node))
+ {
+ // Keep searching for the node on the left
+ position = position->children[kLeft];
+ }
+ else if (node_comp(data_node, key))
+ {
+ // Keep searching for the node on the right
+ position = position->children[kRight];
+ }
+ else
+ {
+ // We found one, keep looking for more on the left
+ found = position;
+ position = position->children[kLeft];
+ }
+ }
+
+ // Return the node found (might be nullptr)
+ return found;
+ }
+
+ //*************************************************************************
+ /// Find the node whose key is not considered to go before the key provided
+ //*************************************************************************
+ Node* find_lower_node(Node* position, const key_value_parameter_t& key) const
+ {
+ // Something at this position? keep going
+ Node* lower_node = nullptr;
+ while (position)
+ {
+ // Downcast lower node to Data_Node reference for key comparisons
+ Data_Node& data_node = imultiset::data_cast(*position);
+ // Compare the key value to the current lower node key value
+ if (node_comp(key, data_node))
+ {
+ lower_node = position;
+ if (position->children[kLeft])
+ {
+ position = position->children[kLeft];
+ }
+ else
+ {
+ // Found lowest node
+ break;
+ }
+ }
+ else if (node_comp(data_node, key))
+ {
+ position = position->children[kRight];
+ }
+ else
+ {
+ // Make note of current position, but keep looking to left for more
+ lower_node = position;
+ position = position->children[kLeft];
+ }
+ }
+
+ // Return the lower_node position found
+ return lower_node;
+ }
+
+ //*************************************************************************
+ /// Find the node whose key is considered to go after the key provided
+ //*************************************************************************
+ Node* find_upper_node(Node* position, const key_value_parameter_t& key) const
+ {
+ // Keep track of parent of last upper node
+ Node* upper_node = nullptr;
+ // Has an equal node been found? start with no
+ bool found = false;
+ while (position)
+ {
+ // Downcast position to Data_Node reference for key comparisons
+ Data_Node& data_node = imultiset::data_cast(*position);
+ // Compare the key value to the current upper node key value
+ if (node_comp(data_node, key))
+ {
+ position = position->children[kRight];
+ }
+ else if (node_comp(key, data_node))
+ {
+ upper_node = position;
+ // If a node equal to key hasn't been found go left
+ if (!found && position->children[kLeft])
+ {
+ position = position->children[kLeft];
+ }
+ else
+ {
+ break;
+ }
+ }
+ else
+ {
+ // We found an equal item, break on next bigger item
+ found = true;
+ next_node(position);
+ }
+ }
+
+ // Return the upper node position found (might be nullptr)
+ return upper_node;
+ }
+
+ //*************************************************************************
+ /// Insert a node.
+ //*************************************************************************
+ Node* insert_node(Node*& position, Data_Node& node)
+ {
+ // Find the location where the node belongs
+ Node* found = position;
+
+ // Was position provided not empty? then find where the node belongs
+ if (position)
+ {
+ // Find the critical parent node (default to nullptr)
+ Node* critical_parent_node = nullptr;
+ Node* critical_node = root_node;
+
+ while (found)
+ {
+ // Search for critical weight node (all nodes whose weight factor
+ // is set to kNeither (balanced)
+ if (kNeither != found->weight)
+ {
+ critical_node = found;
+ }
+
+ // Downcast found to Data_Node class for comparison and other operations
+ Data_Node& found_data_node = imultiset::data_cast(*found);
+
+ // Is the node provided to the left of the current position?
+ if (node_comp(node, found_data_node))
+ {
+ // Update direction taken to insert new node in parent node
+ found->dir = kLeft;
+ }
+ // Is the node provided to the right of the current position?
+ else if (node_comp(found_data_node, node))
+ {
+ // Update direction taken to insert new node in parent node
+ found->dir = kRight;
+ }
+ else
+ {
+ // Update direction taken to insert new node in parent (and
+ // duplicate) node to the right.
+ found->dir = kRight;
+ }
+
+ // Is there a child of this parent node?
+ if (found->children[found->dir])
+ {
+ // Will this node be the parent of the next critical node whose
+ // weight factor is set to kNeither (balanced)?
+ if (kNeither != found->children[found->dir]->weight)
+ {
+ critical_parent_node = found;
+ }
+
+ // Keep looking for empty spot to insert new node
+ found = found->children[found->dir];
+ }
+ else
+ {
+ // Attach node as a child of the parent node found
+ attach_node(found, found->children[found->dir], node);
+
+ // Return newly added node
+ found = found->children[found->dir];
+
+ // Exit loop
+ break;
+ }
+ }
+
+ // Was a critical node found that should be checked for balance?
+ if (critical_node)
+ {
+ if (critical_parent_node == nullptr && critical_node == root_node)
+ {
+ balance_node(root_node);
+ }
+ else if (critical_parent_node == nullptr && critical_node == position)
+ {
+ balance_node(position);
+ }
+ else
+ {
+ balance_node(critical_parent_node->children[critical_parent_node->dir]);
+ }
+ }
+ }
+ else
+ {
+ // Attatch node to current position (which is assumed to be root)
+ attach_node(nullptr, position, node);
+
+ // Return newly added node at current position
+ found = position;
+ }
+
+ // Return the node found (might be nullptr)
+ return found;
+ }
+
+ //*************************************************************************
+ /// Remove the node specified from somewhere starting at the position
+ /// provided
+ //*************************************************************************
+ void remove_node(Node* node)
+ {
+ // If valid found node was provided then proceed with steps 1 through 5
+ if (node)
+ {
+ // Downcast found node provided to Data_Node class
+ Data_Node& data_node = imultiset::data_cast(*node);
+
+ // Keep track of node as found node
+ Node* found = node;
+
+ // Step 1: Mark path from node provided back to the root node using the
+ // internal temporary dir member value and using the parent pointer. This
+ // will allow us to avoid recursion in finding the node in a tree that
+ //might contain duplicate keys to be found.
+ while (node)
+ {
+ if (node->parent)
+ {
+ // Which direction does parent use to get to this node?
+ node->parent->dir =
+ node->parent->children[kLeft] == node ? kLeft : kRight;
+
+ // Make this nodes parent the next node
+ node = node->parent;
+ }
+ else
+ {
+ // Root node found - break loop
+ break;
+ }
+ }
+
+ // Step 2: Follow the path provided above until we reach the node
+ // provided and look for the balance node to start rebalancing the tree
+ // from (up to the replacement node that will be found in step 3)
+ Node* balance = root_node;
+ while (node)
+ {
+ // Did we reach the node provided originally (found) then go to step 3
+ if (node == found)
+ {
+ // Update the direction towards a replacement node at the found node
+ node->dir = node->children[kLeft] ? kLeft : kRight;
+
+ // Exit loop and proceed with step 3
+ break;
+ }
+ else
+ {
+ // If this nodes weight is kNeither or we are taking the shorter path
+ // to the next node and our sibling (on longer path) is balanced then
+ // we need to update the balance node to this node but all our
+ // ancestors will not require rebalancing
+ if ((node->weight == kNeither) ||
+ (node->weight == (1 - node->dir) &&
+ node->children[1 - node->dir]->weight == kNeither))
+ {
+ // Update balance node to this node
+ balance = node;
+ }
+
+ // Keep searching for found in the direction provided in step 1
+ node = node->children[node->dir];
+ }
+ }
+ // The value for node should not be nullptr at this point otherwise
+ // step 1 failed to provide the correct path to found. Step 5 will fail
+ // (probably subtly) if node should be nullptr at this point
+
+ // Step 3: Find the node (node should be equal to found at this point)
+ // to replace found with (might end up equal to found) while also
+ // continuing to update balance the same as in step 2 above.
+ while (node)
+ {
+ // Replacement node found if its missing a child in the replace->dir
+ // value set at the end of step 2 above
+ if (node->children[node->dir] == nullptr)
+ {
+ // Exit loop once node to replace found is determined
+ break;
+ }
+
+ // If this nodes weight is kNeither or we are taking the shorter path
+ // to the next node and our sibling (on longer path) is balanced then
+ // we need to update the balance node to this node but all our
+ // ancestors will not require rebalancing
+ if ((node->weight == kNeither) ||
+ (node->weight == (1 - node->dir) &&
+ node->children[1 - node->dir]->weight == kNeither))
+ {
+ // Update balance node to this node
+ balance = node;
+ }
+
+ // Keep searching for replacement node in the direction specified above
+ node = node->children[node->dir];
+
+ // Downcast node to Data_Node class for comparison operations
+ Data_Node& replace_data_node = imultiset::data_cast(*node);
+
+ // Compare the key provided to the replace data node key
+ if (node_comp(data_node, replace_data_node))
+ {
+ // Update the direction to the replace node
+ node->dir = kLeft;
+ }
+ else if (node_comp(replace_data_node, data_node))
+ {
+ // Update the direction to the replace node
+ node->dir = kRight;
+ }
+ else
+ {
+ // Update the direction to the replace node
+ node->dir = node->children[kLeft] ? kLeft : kRight;
+ }
+ } // while(node)
+
+ // Step 4: Update weights from balance to parent of node determined
+ // in step 3 above rotating (2 or 3 node rotations) as needed.
+ while (balance)
+ {
+ // Break when balance node reaches the parent of replacement node
+ if (balance->children[balance->dir] == nullptr)
+ {
+ break;
+ }
+
+ // If balance node is balanced already (kNeither) then just imbalance
+ // the node in the opposite direction of the node being removed
+ if (balance->weight == kNeither)
+ {
+ balance->weight = 1 - balance->dir;
+ }
+ // If balance node is imbalanced in the opposite direction of the
+ // node being removed then the node now becomes balanced
+ else if (balance->weight == balance->dir)
+ {
+ balance->weight = kNeither;
+ }
+ // Otherwise a rotation is required at this node
+ else
+ {
+ int weight = balance->children[1 - balance->dir]->weight;
+ // Perform a 3 node rotation if weight is same as balance->dir
+ if (weight == balance->dir)
+ {
+ // Is the root node being rebalanced (no parent)
+ if (balance->parent == nullptr)
+ {
+ rotate_3node(root_node, 1 - balance->dir,
+ balance->children[1 - balance->dir]->children[balance->dir]->weight);
+ }
+ else
+ {
+ rotate_3node(balance->parent->children[balance->parent->dir], 1 - balance->dir,
+ balance->children[1 - balance->dir]->children[balance->dir]->weight);
+ }
+ }
+ // Already balanced, rebalance and make it heavy in opposite
+ // direction of the node being removed
+ else if (weight == kNeither)
+ {
+ // Is the root node being rebalanced (no parent)
+ if (balance->parent == nullptr)
+ {
+ rotate_2node(root_node, 1 - balance->dir);
+ root_node->weight = balance->dir;
+ }
+ else
+ {
+ // Balance parent might change during rotate, keep local copy
+ // to old parent so its weight can be updated after the 2 node
+ // rotate is completed
+ Node* old_parent = balance->parent;
+ rotate_2node(balance->parent->children[balance->parent->dir], 1 - balance->dir);
+ old_parent->children[old_parent->dir]->weight = balance->dir;
+ }
+ // Update balance node weight in opposite direction of node removed
+ balance->weight = 1 - balance->dir;
+ }
+ // Rebalance and leave it balanced
+ else
+ {
+ // Is the root node being rebalanced (no parent)
+ if (balance->parent == nullptr)
+ {
+ rotate_2node(root_node, 1 - balance->dir);
+ }
+ else
+ {
+ rotate_2node(balance->parent->children[balance->parent->dir], 1 - balance->dir);
+ }
+ }
+ }
+
+ // Next balance node to consider
+ balance = balance->children[balance->dir];
+ } // while(balance)
+
+ // Step 5: Swap found with node (replacement)
+ if (found->parent)
+ {
+ // Handle traditional case
+ detach_node(found->parent->children[found->parent->dir],
+ node->parent->children[node->parent->dir]);
+ }
+ // Handle root node removal
+ else
+ {
+ // Valid replacement node for root node being removed?
+ if (node->parent)
+ {
+ detach_node(root_node, node->parent->children[node->parent->dir]);
+ }
+ else
+ {
+ // Found node and replacement node are both root node
+ detach_node(root_node, root_node);
+ }
+ }
+
+ // One less.
+ --current_size;
+
+ // Destroy the node detached above
+ destroy_data_node(data_node);
+ } // if(found)
+ }
+
+ // Disable copy construction.
+ imultiset(const imultiset&);
+ };
+}
+
+//***************************************************************************
+/// Equal operator.
+///\param lhs Reference to the first lookup.
+///\param rhs Reference to the second lookup.
+///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
+///\ingroup lookup
+//***************************************************************************
+template <typename T, typename TCompare>
+bool operator ==(const etl::imultiset<T, TCompare>& lhs, const etl::imultiset<T, TCompare>& rhs)
+{
+ return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin());
+}
+
+//***************************************************************************
+/// Not equal operator.
+///\param lhs Reference to the first lookup.
+///\param rhs Reference to the second lookup.
+///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
+///\ingroup lookup
+//***************************************************************************
+template <typename T, typename TCompare>
+bool operator !=(const etl::imultiset<T, TCompare>& lhs, const etl::imultiset<T, TCompare>& rhs)
+{
+ return !(lhs == rhs);
+}
+
+//*************************************************************************
+/// Less than operator.
+///\param lhs Reference to the first list.
+///\param rhs Reference to the second list.
+///\return <b>true</b> if the first list is lexicographically less than the
+/// second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename T, typename TCompare>
+bool operator <(const etl::imultiset<T, TCompare>& lhs, const etl::imultiset<T, TCompare>& rhs)
+{
+ return std::lexicographical_compare(lhs.begin(),
+ lhs.end(),
+ rhs.begin(),
+ rhs.end());
+}
+
+//*************************************************************************
+/// Greater than operator.
+///\param lhs Reference to the first list.
+///\param rhs Reference to the second list.
+///\return <b>true</b> if the first list is lexicographically greater than the
+/// second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename T, typename TCompare>
+bool operator >(const etl::imultiset<T, TCompare>& lhs, const etl::imultiset<T, TCompare>& rhs)
+{
+ return (rhs < lhs);
+}
+
+//*************************************************************************
+/// Less than or equal operator.
+///\param lhs Reference to the first list.
+///\param rhs Reference to the second list.
+///\return <b>true</b> if the first list is lexicographically less than or equal
+/// to the second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename T, typename TCompare>
+bool operator <=(const etl::imultiset<T, TCompare>& lhs, const etl::imultiset<T, TCompare>& rhs)
+{
+ return !(lhs > rhs);
+}
+
+//*************************************************************************
+/// Greater than or equal operator.
+///\param lhs Reference to the first list.
+///\param rhs Reference to the second list.
+///\return <b>true</b> if the first list is lexicographically greater than or
+/// equal to the second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename T, typename TCompare>
+bool operator >=(const etl::imultiset<T, TCompare>& lhs, const etl::imultiset<T, TCompare>& rhs)
+{
+ return !(lhs < rhs);
+}
+
+#ifdef ETL_COMPILER_MICROSOFT
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#undef __ETL_IN_IMULTISET_H__
+
+#endif
diff --git a/lib/etl/instance_count.h b/lib/etl/instance_count.h
new file mode 100644
index 0000000..37e29e3
--- /dev/null
+++ b/lib/etl/instance_count.h
@@ -0,0 +1,83 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_INSTANCE_COUNT__
+#define __ETL_INSTANCE_COUNT__
+
+///\defgroup instance_count instance count
+///\ingroup utilities
+
+namespace etl
+{
+ //***************************************************************************
+ /// Inherit from this to count instances of a type.
+ ///\ingroup reference
+ //***************************************************************************
+ template <typename T>
+ class instance_count
+ {
+ public:
+
+ //*************************************************************************
+ /// Construct and add 1.
+ //*************************************************************************
+ instance_count()
+ {
+ ++how_many;
+ }
+
+ //*************************************************************************
+ /// Destruct and subtract 1.
+ //*************************************************************************
+ virtual ~instance_count()
+ {
+ --how_many;
+ }
+
+ //*************************************************************************
+ /// Get how many instances we have.
+ //*************************************************************************
+ inline static size_t get_instance_count()
+ {
+ return how_many;
+ }
+
+ private:
+
+ /// The count for this type.
+ static size_t how_many;
+ };
+
+ /// Initialisation.
+ template <typename T> size_t instance_count<T>::how_many = 0;
+}
+
+#endif
+
diff --git a/lib/etl/integral_limits.h b/lib/etl/integral_limits.h
new file mode 100644
index 0000000..9dfa737
--- /dev/null
+++ b/lib/etl/integral_limits.h
@@ -0,0 +1,209 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_INTEGRAL_LIMITS__
+#define __ETL_INTEGRAL_LIMITS__
+
+#include <climits>
+#include <stddef.h>
+
+#include "type_traits.h"
+#include "platform.h"
+
+#ifdef ETL_COMPILER_MICROSOFT
+#undef min
+#undef max
+#endif
+
+//*****************************************************************************
+///\defgroup integral_limits integral_limits
+/// A set of templated compile time constants that mirror some of std::numeric_limits funtionality.
+///\ingroup utilities
+//*****************************************************************************
+
+namespace etl
+{
+ //***************************************************************************
+ ///\ingroup integral_limits
+ //***************************************************************************
+ template <typename T>
+ struct integral_limits;
+
+ //***************************************************************************
+ ///\ingroup integral_limits
+ //***************************************************************************
+ template <>
+ struct integral_limits<void>
+ {
+ static const int min = 0;
+ static const int max = 0;
+ static const int bits = 0;
+ static const bool is_signed = false;
+ };
+
+ //***************************************************************************
+ ///\ingroup integral_limits
+ //***************************************************************************
+ template <>
+ struct integral_limits<signed char>
+ {
+ static const signed char min = SCHAR_MIN;
+ static const signed char max = SCHAR_MAX;
+ static const int bits = CHAR_BIT;
+ static const bool is_signed = etl::is_signed<signed char>::value;
+ };
+
+ //***************************************************************************
+ ///\ingroup integral_limits
+ //***************************************************************************
+ template <>
+ struct integral_limits<unsigned char>
+ {
+ static const unsigned char min = 0;
+ static const unsigned char max = UCHAR_MAX;
+ static const int bits = CHAR_BIT;
+ static const bool is_signed = etl::is_signed<unsigned char>::value;
+ };
+
+ //***************************************************************************
+ ///\ingroup integral_limits
+ //***************************************************************************
+ template <>
+ struct integral_limits<char>
+ {
+ static const char min = (etl::is_signed<char>::value) ? SCHAR_MIN : 0;
+ static const char max = (etl::is_signed<char>::value) ? SCHAR_MAX : UCHAR_MAX;
+ static const int bits = CHAR_BIT;
+ static const bool is_signed = etl::is_signed<char>::value;
+ };
+
+ //***************************************************************************
+ ///\ingroup integral_limits
+ //***************************************************************************
+ template <>
+ struct integral_limits<short>
+ {
+ static const short min = SHRT_MIN;
+ static const short max = SHRT_MAX;
+ static const int bits = CHAR_BIT * (sizeof(short) / sizeof(char));
+ static const bool is_signed = etl::is_signed<short>::value;
+ };
+
+ //***************************************************************************
+ ///\ingroup integral_limits
+ //***************************************************************************
+ template <>
+ struct integral_limits<unsigned short>
+ {
+ static const unsigned short min = 0;
+ static const unsigned short max = USHRT_MAX;
+ static const int bits = CHAR_BIT * (sizeof(unsigned short) / sizeof(char));
+ static const bool is_signed = etl::is_signed<unsigned short>::value;
+ };
+
+ //***************************************************************************
+ ///\ingroup integral_limits
+ //***************************************************************************
+ template <>
+ struct integral_limits<int>
+ {
+ static const int min = INT_MIN;
+ static const int max = INT_MAX;
+ static const int bits = CHAR_BIT * (sizeof(int) / sizeof(char));
+ static const bool is_signed = etl::is_signed<int>::value;
+ };
+
+ //***************************************************************************
+ ///\ingroup integral_limits
+ //***************************************************************************
+ template <>
+ struct integral_limits<unsigned int>
+ {
+ static const unsigned int min = 0;
+ static const unsigned int max = UINT_MAX;
+ static const int bits = CHAR_BIT * (sizeof(unsigned int) / sizeof(char));
+ static const bool is_signed = etl::is_signed<unsigned int>::value;
+ };
+
+ //***************************************************************************
+ ///\ingroup integral_limits
+ //***************************************************************************
+ template <>
+ struct integral_limits<long>
+ {
+ static const long min = LONG_MIN;
+ static const long max = LONG_MAX;
+ static const int bits = CHAR_BIT * (sizeof(long) / sizeof(char));
+ static const bool is_signed = etl::is_signed<long>::value;
+ };
+
+ //***************************************************************************
+ ///\ingroup integral_limits
+ //***************************************************************************
+ template <>
+ struct integral_limits<unsigned long>
+ {
+ static const unsigned long min = 0;
+ static const unsigned long max = ULONG_MAX;
+ static const int bits = CHAR_BIT * (sizeof(unsigned long) / sizeof(char));
+ static const bool is_signed = etl::is_signed<unsigned long>::value;
+ };
+
+ //***************************************************************************
+ ///\ingroup integral_limits
+ //***************************************************************************
+ template <>
+ struct integral_limits<long long>
+ {
+ static const long long min = LLONG_MIN;
+ static const long long max = LLONG_MAX;
+ static const int bits = CHAR_BIT * (sizeof(long long) / sizeof(char));
+ static const bool is_signed = etl::is_signed<long long>::value;
+ };
+
+ //***************************************************************************
+ ///\ingroup integral_limits
+ //***************************************************************************
+ template <>
+ struct integral_limits<unsigned long long>
+ {
+ static const unsigned long long min = 0;
+ static const unsigned long long max = ULLONG_MAX;
+ static const int bits = CHAR_BIT * (sizeof(unsigned long long) / sizeof(char));
+ static const bool is_signed = etl::is_signed<unsigned long long>::value;
+ };
+}
+
+#ifdef ETL_COMPILER_MICROSOFT
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#define max(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+
+#endif
diff --git a/lib/etl/intrusive_forward_list.h b/lib/etl/intrusive_forward_list.h
new file mode 100644
index 0000000..21ea1ed
--- /dev/null
+++ b/lib/etl/intrusive_forward_list.h
@@ -0,0 +1,1169 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_INTRUSIVE_FORWARD_LIST__
+#define __ETL_INTRUSIVE_FORWARD_LIST__
+
+#include "platform.h"
+
+#ifdef ETL_COMPILER_MICROSOFT
+#undef min
+#endif
+
+#include <iterator>
+#include <algorithm>
+#include <functional>
+#include <stddef.h>
+
+#include "nullptr.h"
+#include "type_traits.h"
+#include "exception.h"
+#include "error_handler.h"
+#include "intrusive_links.h"
+#include "algorithm.h"
+
+#undef ETL_FILE
+#define ETL_FILE "20"
+
+namespace etl
+{
+ //***************************************************************************
+ /// Exception for the intrusive_forward_list.
+ ///\ingroup intrusive_forward_list
+ //***************************************************************************
+ class intrusive_forward_list_exception : public exception
+ {
+ public:
+
+ intrusive_forward_list_exception(string_type what, string_type file_name, numeric_type line_number)
+ : exception(what, file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// Empty exception for the intrusive_forward_list.
+ ///\ingroup intrusive_forward_list
+ //***************************************************************************
+ class intrusive_forward_list_empty : public intrusive_forward_list_exception
+ {
+ public:
+
+ intrusive_forward_list_empty(string_type file_name, numeric_type line_number)
+ : intrusive_forward_list_exception(ETL_ERROR_TEXT("intrusive_forward_list:empty", ETL_FILE"A"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// Iterator exception for the intrusive_forward_list.
+ ///\ingroup intrusive_forward_list
+ //***************************************************************************
+ class intrusive_forward_list_iterator_exception : public intrusive_forward_list_exception
+ {
+ public:
+
+ intrusive_forward_list_iterator_exception(string_type file_name, numeric_type line_number)
+ : intrusive_forward_list_exception(ETL_ERROR_TEXT("intrusive_forward_list:iterator", ETL_FILE"B"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// Index exception for the intrusive_forward_list.
+ ///\ingroup intrusive_forward_list
+ //***************************************************************************
+ class intrusive_forward_list_index_exception : public intrusive_forward_list_exception
+ {
+ public:
+
+ intrusive_forward_list_index_exception(string_type file_name, numeric_type line_number)
+ : intrusive_forward_list_exception(ETL_ERROR_TEXT("intrusive_forward_list:bounds", ETL_FILE"C"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// Unsorted exception for the intrusive_forward_list.
+ ///\ingroup intrusive_list
+ //***************************************************************************
+ class intrusive_forward_list_unsorted : public intrusive_forward_list_exception
+ {
+ public:
+
+ intrusive_forward_list_unsorted(string_type file_name, numeric_type line_number)
+ : intrusive_forward_list_exception(ETL_ERROR_TEXT("intrusive_forward_list:unsorted", ETL_FILE"D"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// An intrusive forward list.
+ ///\ingroup intrusive_forward_list
+ ///\note TLink must be a base of TValue.
+ //***************************************************************************
+ template <typename TValue, typename TLink = etl::forward_link<0> >
+ class intrusive_forward_list
+ {
+ public:
+
+ // Node typedef.
+ typedef TLink link_type;
+
+ // STL style typedefs.
+ typedef TValue value_type;
+ typedef value_type* pointer;
+ typedef const value_type* const_pointer;
+ typedef value_type& reference;
+ typedef const value_type& const_reference;
+ typedef size_t size_type;
+
+ enum
+ {
+ // The count option is based on the type of link.
+ COUNT_OPTION = ((TLink::OPTION == etl::link_option::AUTO) ||
+ (TLink::OPTION == etl::link_option::CHECKED)) ? etl::count_option::SLOW_COUNT : etl::count_option::FAST_COUNT
+ };
+
+ typedef intrusive_forward_list<TValue, TLink> list_type;
+
+ //*************************************************************************
+ /// iterator.
+ //*************************************************************************
+ class iterator : public std::iterator<std::forward_iterator_tag, value_type>
+ {
+ public:
+
+ friend class intrusive_forward_list;
+
+ iterator()
+ : p_value(nullptr)
+ {
+ }
+
+ iterator(value_type& value)
+ : p_value(&value)
+ {
+ }
+
+ iterator(const iterator& other)
+ : p_value(other.p_value)
+ {
+ }
+
+ iterator& operator ++()
+ {
+ // Read the appropriate 'etl_next'.
+ p_value = static_cast<value_type*>(p_value->link_type::etl_next);
+ return *this;
+ }
+
+ iterator operator ++(int)
+ {
+ iterator temp(*this);
+ // Read the appropriate 'etl_next'.
+ p_value = static_cast<value_type*>(p_value->link_type::etl_next);
+ return temp;
+ }
+
+ iterator operator =(const iterator& other)
+ {
+ p_value = other.p_value;
+ return *this;
+ }
+
+ reference operator *()
+ {
+ return *p_value;
+ }
+
+ const_reference operator *() const
+ {
+ return *p_value;
+ }
+
+ pointer operator &()
+ {
+ return p_value;
+ }
+
+ const_pointer operator &() const
+ {
+ return p_value;
+ }
+
+ pointer operator ->()
+ {
+ return p_value;
+ }
+
+ const_pointer operator ->() const
+ {
+ return p_value;
+ }
+
+ friend bool operator == (const iterator& lhs, const iterator& rhs)
+ {
+ return lhs.p_value == rhs.p_value;
+ }
+
+ friend bool operator != (const iterator& lhs, const iterator& rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+ private:
+
+ value_type* p_value;
+ };
+
+ //*************************************************************************
+ /// const_iterator
+ //*************************************************************************
+ class const_iterator : public std::iterator<std::forward_iterator_tag, const value_type>
+ {
+ public:
+
+ friend class intrusive_forward_list;
+
+ const_iterator()
+ : p_value(nullptr)
+ {
+ }
+
+ const_iterator(const value_type& value)
+ : p_value(&value)
+ {
+ }
+
+ const_iterator(const typename intrusive_forward_list::iterator& other)
+ : p_value(other.p_value)
+ {
+ }
+
+ const_iterator(const const_iterator& other)
+ : p_value(other.p_value)
+ {
+ }
+
+ const_iterator& operator ++()
+ {
+ // Read the appropriate 'etl_next'.
+ p_value = static_cast<value_type*>(p_value->link_type::etl_next);
+ return *this;
+ }
+
+ const_iterator operator ++(int)
+ {
+ const_iterator temp(*this);
+ // Read the appropriate 'etl_next'.
+ p_value = static_cast<value_type*>(p_value->link_type::etl_next);
+ return temp;
+ }
+
+ const_iterator operator =(const const_iterator& other)
+ {
+ p_value = other.p_value;
+ return *this;
+ }
+
+ const_reference operator *() const
+ {
+ return *p_value;
+ }
+
+ const_pointer operator &() const
+ {
+ return p_value;
+ }
+
+ const_pointer operator ->() const
+ {
+ return p_value;
+ }
+
+ friend bool operator == (const const_iterator& lhs, const const_iterator& rhs)
+ {
+ return lhs.p_value == rhs.p_value;
+ }
+
+ friend bool operator != (const const_iterator& lhs, const const_iterator& rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+ private:
+
+ const value_type* p_value;
+ };
+
+ typedef typename std::iterator_traits<iterator>::difference_type difference_type;
+
+ //*************************************************************************
+ /// Constructor.
+ //*************************************************************************
+ intrusive_forward_list()
+ {
+ initialise();
+ }
+
+ //*************************************************************************
+ /// Constructor from range
+ //*************************************************************************
+ template <typename TIterator>
+ intrusive_forward_list(TIterator first, TIterator last)
+ {
+ assign(first, last);
+ }
+
+ //*************************************************************************
+ /// Gets the beginning of the intrusive_forward_list.
+ //*************************************************************************
+ iterator begin()
+ {
+ return iterator(static_cast<value_type&>(get_head()));
+ }
+
+ //*************************************************************************
+ /// Gets the beginning of the intrusive_forward_list.
+ //*************************************************************************
+ const_iterator begin() const
+ {
+ return const_iterator(static_cast<const value_type&>(get_head()));
+ }
+
+ //*************************************************************************
+ /// Gets before the beginning of the intrusive_forward_list.
+ //*************************************************************************
+ iterator before_begin()
+ {
+ return iterator(static_cast<value_type&>(start_link));
+ }
+
+ //*************************************************************************
+ /// Gets before the beginning of the intrusive_forward_list.
+ //*************************************************************************
+ const_iterator before_begin() const
+ {
+ return const_iterator(static_cast<const value_type&>(start_link));
+ }
+
+ //*************************************************************************
+ /// Gets the beginning of the intrusive_forward_list.
+ //*************************************************************************
+ const_iterator cbegin() const
+ {
+ return const_iterator(static_cast<const value_type&>(get_head()));
+ }
+
+ //*************************************************************************
+ /// Gets the end of the intrusive_forward_list.
+ //*************************************************************************
+ iterator end()
+ {
+ return iterator();
+ }
+
+ //*************************************************************************
+ /// Gets the end of the intrusive_forward_list.
+ //*************************************************************************
+ const_iterator end() const
+ {
+ return const_iterator();
+ }
+
+ //*************************************************************************
+ /// Gets the end of the intrusive_forward_list.
+ //*************************************************************************
+ const_iterator cend() const
+ {
+ return const_iterator();
+ }
+
+ //*************************************************************************
+ /// Clears the intrusive_forward_list.
+ //*************************************************************************
+ void clear()
+ {
+ initialise();
+ }
+
+ //*************************************************************************
+ /// Gets a reference to the first element.
+ //*************************************************************************
+ reference front()
+ {
+ return static_cast<value_type&>(get_head());
+ }
+
+ //*************************************************************************
+ /// Gets a const reference to the first element.
+ //*************************************************************************
+ const_reference front() const
+ {
+ return static_cast<const value_type&>(get_head());;
+ }
+
+ //*************************************************************************
+ /// Assigns a range of values to the intrusive_forward_list.
+ /// If ETL_THROW_EXCEPTIONS & _DEBUG are defined throws forward_list_iterator if the iterators are reversed.
+ //*************************************************************************
+ template <typename TIterator>
+ void assign(TIterator first, TIterator last)
+ {
+#ifdef _DEBUG
+ difference_type count = std::distance(first, last);
+ ETL_ASSERT(count >= 0, ETL_ERROR(intrusive_forward_list_iterator_exception));
+#endif
+
+ initialise();
+
+ link_type* p_last_link = &start_link;
+
+ // Add all of the elements.
+ while (first != last)
+ {
+ link_type& link = *first++;
+ etl::link_splice<link_type>(p_last_link, link);
+ p_last_link = &link;
+ ++current_size;
+ }
+ }
+
+ //*************************************************************************
+ /// Pushes a value to the front of the intrusive_forward_list.
+ //*************************************************************************
+ void push_front(link_type& value)
+ {
+ insert_link_after(start_link, value);
+ }
+
+ //*************************************************************************
+ /// Removes a value from the front of the intrusive_forward_list.
+ //*************************************************************************
+ void pop_front()
+ {
+#if defined(ETL_CHECK_PUSH_POP)
+ ETL_ASSERT(!empty(), ETL_ERROR(intrusive_forward_list_empty));
+#endif
+ remove_link_after(start_link);
+ }
+
+ //*************************************************************************
+ /// Reverses the intrusive_forward_list.
+ //*************************************************************************
+ void reverse()
+ {
+ if (is_trivial_list())
+ {
+ return;
+ }
+
+ link_type* first = nullptr; // To keep first link
+ link_type* second = start_link.etl_next; // To keep second link
+ link_type* track = start_link.etl_next; // Track the list
+
+ while (track != NULL)
+ {
+ track = track->etl_next; // Track point to next link;
+ second->etl_next = first; // Second link point to first
+ first = second; // Move first link to next
+ second = track; // Move second link to next
+ }
+
+ etl::link<link_type>(start_link, first);
+ }
+
+ //*************************************************************************
+ /// Inserts a value to the intrusive_forward_list after the specified position.
+ /// Checks that the value is unlinked if CHECKED.
+ //*************************************************************************
+ iterator insert_after(iterator position, value_type& value)
+ {
+ if (TLink::OPTION == etl::link_option::CHECKED)
+ {
+ ETL_ASSERT(!value.TLink::is_linked(), ETL_ERROR(etl::not_unlinked_exception));
+ }
+
+ insert_link_after(*position.p_value, value);
+ return iterator(value);
+ }
+
+ //*************************************************************************
+ /// Inserts a range of values to the intrusive_forward_list after the specified position.
+ /// Checks that the values are unlinked if CHECKED.
+ //*************************************************************************
+ template <typename TIterator>
+ void insert_after(iterator position, TIterator first, TIterator last)
+ {
+ while (first != last)
+ {
+ if (TLink::OPTION == etl::link_option::CHECKED)
+ {
+ ETL_ASSERT(!position.p_value->TLink::is_linked(), ETL_ERROR(etl::not_unlinked_exception));
+ }
+
+ // Set up the next free link.
+ insert_link_after(*position.p_value, *first++);
+ ++position;
+ }
+ }
+
+ //*************************************************************************
+ /// Erases the value at the specified position.
+ /// Clears the link after erasing if CHECKED.
+ //*************************************************************************
+ iterator erase_after(iterator position)
+ {
+ iterator next(position);
+ ++next;
+ ++next;
+
+ remove_link_after(*position.p_value);
+
+ if (TLink::OPTION == etl::link_option::CHECKED)
+ {
+ position.p_value->TLink::clear();
+ }
+
+ return next;
+ }
+
+ //*************************************************************************
+ /// Erases a range of elements.
+ /// Clears the links after erasing if CHECKED.
+ //*************************************************************************
+ iterator erase_after(iterator first, iterator last)
+ {
+ link_type* p_first = first.p_value;
+ link_type* p_last = last.p_value;
+ link_type* p_next = p_first->etl_next;
+
+ // Join the ends.
+ etl::link<link_type>(p_first, p_last);
+
+ p_first = p_next;
+
+ // Erase the ones in between.
+ while (p_first != p_last)
+ {
+ // One less.
+ --current_size;
+
+ p_next = p_first->etl_next; // Remember the next link.
+
+ if (TLink::OPTION == etl::link_option::CHECKED)
+ {
+ p_first->TLink::clear(); // Clear the link.
+ }
+
+ p_first = p_next; // Move to the next link.
+ }
+
+ if (p_next == nullptr)
+ {
+ return end();
+ }
+ else
+ {
+ return iterator(*static_cast<value_type*>(p_last));
+ }
+ }
+
+ //*************************************************************************
+ /// Removes all but the one element from every consecutive group of equal
+ /// elements in the container.
+ //*************************************************************************
+ template <typename TIsEqual>
+ void unique(TIsEqual isEqual)
+ {
+ if (empty())
+ {
+ return;
+ }
+
+ link_type* last = &get_head();
+ link_type* current = last->etl_next;
+
+ while (current != nullptr)
+ {
+ // Is this value the same as the last?
+ if (isEqual(*static_cast<value_type*>(current), *static_cast<value_type*>(last)))
+ {
+ remove_link_after(*last);
+ }
+ else
+ {
+ // Move on one.
+ last = current;
+ }
+
+ current = last->etl_next;
+ }
+ }
+
+ //*************************************************************************
+ /// Sort using in-place merge sort algorithm.
+ //*************************************************************************
+ void sort()
+ {
+ sort(std::less<value_type>());
+ }
+
+ //*************************************************************************
+ /// Sort using in-place merge sort algorithm.
+ /// Uses a supplied predicate function or functor.
+ /// This is not my algorithm. I got it off the web somewhere.
+ //*************************************************************************
+ template <typename TCompare>
+ void sort(TCompare compare)
+ {
+ iterator i_left;
+ iterator i_right;
+ iterator i_link;
+ iterator i_head;
+ iterator i_tail;
+ int list_size = 1;
+ int number_of_merges;
+ int left_size;
+ int right_size;
+
+ if (is_trivial_list())
+ {
+ return;
+ }
+
+ while (true)
+ {
+ i_left = begin();
+ i_head = before_begin();
+ i_tail = before_begin();
+
+ number_of_merges = 0; // Count the number of merges we do in this pass.
+
+ while (i_left != end())
+ {
+ ++number_of_merges; // There exists a merge to be done.
+ i_right = i_left;
+ left_size = 0;
+
+ // Step 'list_size' places along from left
+ for (int i = 0; i < list_size; ++i)
+ {
+ ++left_size;
+
+ ++i_right;
+
+ if (i_right == end())
+ {
+ break;
+ }
+ }
+
+ // If right hasn't fallen off end, we have two lists to merge.
+ right_size = list_size;
+
+ // Now we have two lists. Merge them.
+ while (left_size > 0 || (right_size > 0 && i_right != end()))
+ {
+ // Decide whether the next link of merge comes from left or right.
+ if (left_size == 0)
+ {
+ // Left is empty. The link must come from right.
+ i_link = i_right;
+ ++i_right;
+ --right_size;
+ }
+ else if (right_size == 0 || i_right == end())
+ {
+ // Right is empty. The link must come from left.
+ i_link = i_left;
+ ++i_left;
+ --left_size;
+ }
+ else if (compare(*i_left, *i_right))
+ {
+ // First link of left is lower or same. The link must come from left.
+ i_link = i_left;
+ ++i_left;
+ --left_size;
+ }
+ else
+ {
+ // First link of right is lower. The link must come from right.
+ i_link = i_right;
+ ++i_right;
+ --right_size;
+ }
+
+ // Add the next link to the merged head.
+ if (i_head == before_begin())
+ {
+ etl::link<link_type>(i_head.p_value, i_link.p_value);
+ i_head = i_link;
+ i_tail = i_link;
+ }
+ else
+ {
+ etl::link<link_type>(i_tail.p_value, i_link.p_value);
+ i_tail = i_link;
+ }
+
+ i_tail.p_value->link_type::etl_next = nullptr;
+ }
+
+ // Now left has stepped `list_size' places along, and right has too.
+ i_left = i_right;
+ }
+
+ // If we have done only one merge, we're finished.
+ if (number_of_merges <= 1) // Allow for number_of_merges == 0, the empty head case
+ {
+ return;
+ }
+
+ // Otherwise repeat, merging lists twice the size
+ list_size *= 2;
+ }
+ }
+
+ //*************************************************************************
+ // Removes the values specified.
+ //*************************************************************************
+ void remove(const_reference value)
+ {
+ iterator i_item = begin();
+ iterator i_last_item = before_begin();
+
+ while (i_item != end())
+ {
+ if (*i_item == value)
+ {
+ i_item = erase_after(i_last_item);
+ }
+ else
+ {
+ ++i_item;
+ ++i_last_item;
+ }
+ }
+ }
+
+ //*************************************************************************
+ /// Removes according to a predicate.
+ //*************************************************************************
+ template <typename TPredicate>
+ void remove_if(TPredicate predicate)
+ {
+ iterator i_item = begin();
+ iterator i_last_item = before_begin();
+
+ while (i_item != end())
+ {
+ if (predicate(*i_item))
+ {
+ i_item = erase_after(i_last_item);
+ }
+ else
+ {
+ ++i_item;
+ ++i_last_item;
+ }
+ }
+ }
+
+ //*************************************************************************
+ /// Returns true if the list has no elements.
+ //*************************************************************************
+ bool empty() const
+ {
+ return start_link.etl_next == nullptr;
+ }
+
+ //*************************************************************************
+ /// Returns the number of elements.
+ //*************************************************************************
+ size_t size() const
+ {
+ if (COUNT_OPTION == etl::count_option::SLOW_COUNT)
+ {
+ return std::distance(cbegin(), cend());
+ }
+ else
+ {
+ return current_size.get_count();
+ }
+ }
+
+ //*************************************************************************
+ /// Splice another list into this one.
+ //*************************************************************************
+ void splice_after(iterator position, etl::intrusive_forward_list<TValue, TLink>& list)
+ {
+ // No point splicing to ourself!
+ if (&list != this)
+ {
+ if (!list.empty())
+ {
+ link_type& first = list.get_head();
+
+ if (COUNT_OPTION == etl::count_option::FAST_COUNT)
+ {
+ if (&list != this)
+ {
+ current_size += list.size();
+ }
+ }
+
+ link_type& before = *position.p_value;
+ link_type& after = *position.p_value->link_type::etl_next;
+
+ etl::link<link_type>(before, first);
+
+ link_type* last = &before;
+ while (last->link_type::etl_next != nullptr)
+ {
+ last = last->link_type::etl_next;
+ }
+
+ etl::link<link_type>(last, after);
+
+ list.clear();
+ }
+ }
+ }
+
+ //*************************************************************************
+ /// Splice an element from another list into this one.
+ //*************************************************************************
+ void splice(iterator position, etl::intrusive_forward_list<TValue, TLink>& list, iterator isource)
+ {
+ link_type& before = *position.p_value;
+
+ etl::unlink<link_type>(*isource.p_value);
+ etl::link_splice<link_type>(before, *isource.p_value);
+
+ if (COUNT_OPTION == etl::count_option::FAST_COUNT)
+ {
+ if (&list != this)
+ {
+ ++current_size;
+ --list.current_size;
+ }
+ }
+ }
+
+ //*************************************************************************
+ /// Splice a range of elements from another list into this one.
+ //*************************************************************************
+ void splice_after(iterator position, etl::intrusive_forward_list<TValue, TLink>& list, iterator begin_, iterator end_)
+ {
+ if (!list.empty())
+ {
+ if (COUNT_OPTION == etl::count_option::FAST_COUNT)
+ {
+ if (&list != this)
+ {
+ size_t n = std::distance(begin_, end_) - 1;
+ current_size += n;
+ list.current_size -= n;
+ }
+ }
+
+ link_type* first = begin_.p_value;
+ link_type* last = first;
+
+ while (last->link_type::etl_next != end_.p_value)
+ {
+ last = last->link_type::etl_next;
+ }
+
+ // Unlink from the source list.
+ link_type* first_next = first->link_type::etl_next;
+ etl::unlink_after(*first, *last);
+
+ // Fix our links.
+ link_type* before = position.p_value;
+
+ etl::link_splice<link_type>(*before, *first_next, *last);
+ }
+ }
+
+ //*************************************************************************
+ /// Merge another list into this one. Both lists should be sorted.
+ //*************************************************************************
+ void merge(list_type& list)
+ {
+ merge(list, std::less<value_type>());
+ }
+
+ //*************************************************************************
+ /// Merge another list into this one. Both lists should be sorted.
+ //*************************************************************************
+ template <typename TCompare>
+ void merge(list_type& list, TCompare compare)
+ {
+ if (!list.empty())
+ {
+#if _DEBUG
+ ETL_ASSERT(etl::is_sorted(list.begin(), list.end(), compare), ETL_ERROR(intrusive_forward_list_unsorted));
+ ETL_ASSERT(etl::is_sorted(begin(), end(), compare), ETL_ERROR(intrusive_forward_list_unsorted));
+#endif
+
+ value_type* other_begin = static_cast<value_type*>(&list.get_head());
+ value_type* other_terminal = nullptr;
+
+ value_type* before = static_cast<value_type*>(&start_link);
+ value_type* before_next = get_next(before);
+ value_type* terminal = nullptr;
+
+ while ((before->link_type::etl_next != terminal) && (other_begin != other_terminal))
+ {
+ // Find the place to insert.
+ while ((before_next != terminal) && !(compare(*other_begin, *before_next)))
+ {
+ before = before_next;
+ before_next = get_next(before_next);
+ }
+
+ // Insert.
+ if (before_next != terminal)
+ {
+ while ((other_begin != other_terminal) && (compare(*other_begin, *before_next)))
+ {
+ value_type* value = other_begin;
+ other_begin = get_next(other_begin);
+ etl::link_splice<link_type>(*before, *value);
+ before = get_next(before);
+ }
+ }
+ }
+
+ // Any left over?
+ if (before_next == terminal)
+ {
+ while (other_begin != other_terminal)
+ {
+ value_type* value = other_begin;
+ other_begin = get_next(other_begin);
+ etl::link_splice<link_type>(*before, *value);
+ before = get_next(before);
+ }
+ }
+
+ if (COUNT_OPTION == etl::count_option::FAST_COUNT)
+ {
+ current_size += list.size();
+ }
+
+ list.clear();
+ }
+ }
+
+ private:
+
+ link_type start_link; ///< The link that acts as the intrusive_forward_list start.
+
+ //*************************************************************************
+ /// Counter type based on count option.
+ //*************************************************************************
+ template <const size_t OPTION, bool dummy = true>
+ class counter_type
+ {
+ };
+
+ //*************************************************************************
+ /// Slow type.
+ //*************************************************************************
+ template <bool dummy>
+ class counter_type<etl::count_option::SLOW_COUNT, dummy>
+ {
+ public:
+
+ counter_type& operator ++()
+ {
+ return *this;
+ }
+
+ counter_type& operator --()
+ {
+ return *this;
+ }
+
+ counter_type& operator =(size_t new_count)
+ {
+ return *this;
+ }
+
+ counter_type& operator +=(size_t diff)
+ {
+ return *this;
+ }
+
+ counter_type& operator -=(size_t diff)
+ {
+ return *this;
+ }
+
+ size_t get_count() const
+ {
+ return 0;
+ }
+ };
+
+ //*************************************************************************
+ /// Fast type.
+ //*************************************************************************
+ template <bool dummy>
+ class counter_type<etl::count_option::FAST_COUNT, dummy>
+ {
+ public:
+
+ counter_type()
+ : count(0)
+ {
+ }
+
+ counter_type& operator ++()
+ {
+ ++count;
+ return *this;
+ }
+
+ counter_type& operator --()
+ {
+ --count;
+ return *this;
+ }
+
+ counter_type& operator =(size_t new_count)
+ {
+ count = new_count;
+ return *this;
+ }
+
+ counter_type& operator +=(size_t diff)
+ {
+ count += diff;
+ return *this;
+ }
+
+ counter_type& operator -=(size_t diff)
+ {
+ count -= diff;
+ return *this;
+ }
+
+ size_t get_count() const
+ {
+ return count;
+ }
+
+ size_t count;
+ };
+
+ counter_type<COUNT_OPTION> current_size; ///< Counts the number of elements in the list.
+
+ //*************************************************************************
+ /// Is the intrusive_forward_list a trivial length?
+ //*************************************************************************
+ bool is_trivial_list() const
+ {
+ return (start_link.link_type::etl_next == nullptr) || (start_link.link_type::etl_next->etl_next == nullptr);;
+ }
+
+ //*************************************************************************
+ /// Insert a link.
+ //*************************************************************************
+ void insert_link_after(link_type& position, link_type& link)
+ {
+ // Connect to the intrusive_forward_list.
+ etl::link_splice<link_type>(position, link);
+ ++current_size;
+ }
+
+ //*************************************************************************
+ /// Remove a link.
+ //*************************************************************************
+ void remove_link_after(link_type& link)
+ {
+ if (link.etl_next != nullptr)
+ {
+ etl::unlink_after<link_type>(link);
+ --current_size;
+ }
+ }
+
+ //*************************************************************************
+ /// Get the head link.
+ //*************************************************************************
+ link_type& get_head()
+ {
+ return *start_link.etl_next;
+ }
+
+ //*************************************************************************
+ /// Get the head link.
+ //*************************************************************************
+ const link_type& get_head() const
+ {
+ return *start_link.etl_next;
+ }
+
+ //*************************************************************************
+ /// Get the next value.
+ //*************************************************************************
+ value_type* get_next(link_type* link) const
+ {
+ return static_cast<value_type*>(link->etl_next);
+ }
+
+ //*************************************************************************
+ /// Initialise the intrusive_forward_list.
+ //*************************************************************************
+ void initialise()
+ {
+ start_link.etl_next = nullptr;
+ current_size = 0;
+ }
+
+ // Disabled.
+ intrusive_forward_list(const intrusive_forward_list& other);
+ intrusive_forward_list& operator = (const intrusive_forward_list& rhs);
+ };
+}
+
+#ifdef ETL_COMPILER_MICROSOFT
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#undef ETL_FILE
+
+#endif
diff --git a/lib/etl/intrusive_links.h b/lib/etl/intrusive_links.h
new file mode 100644
index 0000000..00ebb14
--- /dev/null
+++ b/lib/etl/intrusive_links.h
@@ -0,0 +1,827 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_INTRUSIVE_LINKS__
+#define __ETL_INTRUSIVE_LINKS__
+
+#include <assert.h>
+#include <utility>
+
+#include "nullptr.h"
+#include "type_traits.h"
+#include "exception.h"
+#include "error_handler.h"
+
+#undef ETL_FILE
+#define ETL_FILE "22"
+
+//*****************************************************************************
+// Note:
+// The link functions work slightly differently to the STL 'insert' convention
+// in that the second link parameter will be inserted after the first.
+// i.e.
+// If the list contains '1', '2', '3', '4' and "link_splice '2','5'" is invoked the
+// resulting list will contain '1', '2', '5', '3', '4'
+// This is to maintain consistency between forward and bidirectional links
+// and also is intuitive.
+//*****************************************************************************
+
+namespace etl
+{
+ namespace link_option
+ {
+ enum
+ {
+ DEFAULT,
+ AUTO,
+ CHECKED
+ };
+ }
+
+ namespace count_option
+ {
+ enum
+ {
+ SLOW_COUNT,
+ FAST_COUNT
+ };
+ }
+
+ //***************************************************************************
+ /// Link exception.
+ //***************************************************************************
+ class link_exception : public etl::exception
+ {
+ public:
+
+ link_exception(string_type what, string_type file_name, numeric_type line_number)
+ : exception(what, file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// not unlinked exception.
+ //***************************************************************************
+ class not_unlinked_exception : public etl::link_exception
+ {
+ public:
+
+ not_unlinked_exception(string_type file_name, numeric_type line_number)
+ : link_exception(ETL_ERROR_TEXT("link:still linked", ETL_FILE"A"), file_name, line_number)
+ {
+ }
+ };
+
+ namespace __private_intrusive_links__
+ {
+ //***************************************************************************
+ /// A forward link base.
+ //***************************************************************************
+ template <typename TLink, const size_t ID_, const size_t OPTION_>
+ struct forward_link_base
+ {
+ enum
+ {
+ ID = ID_,
+ OPTION = OPTION_
+ };
+
+ void clear()
+ {
+ etl_next = nullptr;
+ }
+
+ bool is_linked() const
+ {
+ return etl_next != nullptr;
+ }
+
+ TLink* etl_next;
+ };
+ }
+
+ //***************************************************************************
+ /// A forward link.
+ //***************************************************************************
+ template <const size_t ID_, const size_t OPTION_ = etl::link_option::DEFAULT>
+ struct forward_link
+ : public __private_intrusive_links__::forward_link_base<forward_link<ID_, OPTION_>, ID_, OPTION_>
+ {
+ };
+
+ //******************************************************************
+ // There is no valid specialisation for auto link
+ //******************************************************************
+ template <const size_t ID_>
+ struct forward_link<ID_, etl::link_option::AUTO>
+ : public __private_intrusive_links__::forward_link_base<forward_link<ID_, etl::link_option::AUTO>, ID_, etl::link_option::AUTO>
+ {
+ forward_link()
+ {
+ this->clear();
+ }
+ };
+
+ //******************************************************************
+ // Specialisation for checked unlink option.
+ // An error will be generated if the links are valid when the object
+ // is destroyed.
+ //******************************************************************
+ template <const size_t ID_>
+ struct forward_link<ID_, etl::link_option::CHECKED>
+ : public __private_intrusive_links__::forward_link_base<forward_link<ID_, etl::link_option::CHECKED>, ID_, etl::link_option::CHECKED>
+ {
+ forward_link()
+ {
+ this->clear();
+ }
+
+ ~forward_link()
+ {
+ assert(this->etl_next != nullptr);
+ }
+ };
+
+ // Reference, Reference
+ template <typename TLink>
+ typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID, TLink::OPTION> >::value, void>::type
+ link(TLink& lhs, TLink& rhs)
+ {
+ lhs.etl_next = &rhs;
+ }
+
+ // Reference, Reference
+ template <typename TLink>
+ typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID, TLink::OPTION> >::value, void>::type
+ link_splice(TLink& lhs, TLink& rhs)
+ {
+ rhs.etl_next = lhs.etl_next;
+ lhs.etl_next = &rhs;
+ }
+
+ // Pointer, Pointer
+ template <typename TLink>
+ typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID, TLink::OPTION> >::value, void>::type
+ link(TLink* lhs, TLink* rhs)
+ {
+ if (lhs != nullptr)
+ {
+ lhs->etl_next = rhs;
+ }
+ }
+
+ // Pointer, Pointer
+ template <typename TLink>
+ typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID, TLink::OPTION> >::value, void>::type
+ link_splice(TLink* lhs, TLink* rhs)
+ {
+ if (lhs != nullptr)
+ {
+ if (rhs != nullptr)
+ {
+ rhs->etl_next = lhs->etl_next;
+ }
+
+ lhs->etl_next = rhs;
+ }
+ }
+
+ // Reference, Pointer
+ template <typename TLink>
+ typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID, TLink::OPTION> >::value, void>::type
+ link(TLink& lhs, TLink* rhs)
+ {
+ lhs.etl_next = rhs;
+ }
+
+ // Reference, Pointer
+ template <typename TLink>
+ typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID, TLink::OPTION> >::value, void>::type
+ link_splice(TLink& lhs, TLink* rhs)
+ {
+ if (rhs != nullptr)
+ {
+ rhs->etl_next = lhs.etl_next;
+ }
+
+ lhs.etl_next = rhs;
+ }
+
+ // Pointer, Reference
+ template <typename TLink>
+ typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID, TLink::OPTION> >::value, void>::type
+ link(TLink* lhs, TLink& rhs)
+ {
+ if (lhs != nullptr)
+ {
+ lhs->etl_next = &rhs;
+ }
+ }
+
+ // Pointer, Reference
+ template <typename TLink>
+ typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID, TLink::OPTION> >::value, void>::type
+ link_splice(TLink* lhs, TLink& rhs)
+ {
+ if (lhs != nullptr)
+ {
+ rhs.etl_next = lhs->etl_next;
+ lhs->etl_next = &rhs;
+ }
+ }
+
+ // Reference, Reference, Reference
+ template <typename TLink>
+ typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID, TLink::OPTION> >::value, void>::type
+ link_splice(TLink& lhs, TLink& first, TLink& last)
+ {
+ last.etl_next = lhs.etl_next;
+ lhs.etl_next = &first;
+ }
+
+ // Pointer, Reference, Reference
+ template <typename TLink>
+ typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID, TLink::OPTION> >::value, void>::type
+ link_splice(TLink* lhs, TLink& first, TLink& last)
+ {
+ if (lhs != nullptr)
+ {
+ last.etl_next = lhs->etl_next;
+ lhs->etl_next = &first;
+ }
+ else
+ {
+ last.etl_next = nullptr;
+ }
+ }
+
+ // Reference
+ template <typename TLink>
+ typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID, TLink::OPTION> >::value, void>::type
+ unlink_after(TLink& node)
+ {
+ if (node.etl_next != nullptr)
+ {
+ TLink* unlinked_node = node.etl_next;
+ node.etl_next = unlinked_node->etl_next;
+
+ if ((int(TLink::OPTION) == etl::link_option::AUTO) ||
+ (int(TLink::OPTION) == etl::link_option::CHECKED))
+ {
+ unlinked_node->clear();
+ }
+ }
+ }
+
+ // Reference, Reference
+ template <typename TLink>
+ typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID, TLink::OPTION> >::value, void>::type
+ unlink_after(TLink& before, TLink& last)
+ {
+ before.etl_next = last.etl_next;
+
+ if ((int(TLink::OPTION) == etl::link_option::AUTO) ||
+ (int(TLink::OPTION) == etl::link_option::CHECKED))
+ {
+ last.clear();
+ }
+ }
+
+ namespace __private_intrusive_links__
+ {
+ //***************************************************************************
+ /// A bidirectional link base.
+ //***************************************************************************
+ template <typename TLink, const size_t ID_, const size_t OPTION_>
+ struct bidirectional_link_base
+ {
+ enum
+ {
+ ID = ID_,
+ OPTION = OPTION_
+ };
+
+ void clear()
+ {
+ etl_previous = nullptr;
+ etl_next = nullptr;
+ }
+
+ bool is_linked() const
+ {
+ return (etl_previous != nullptr) || (etl_next != nullptr);
+ }
+
+ void reverse()
+ {
+ std::swap(etl_previous, etl_next);
+ }
+
+ TLink* etl_previous;
+ TLink* etl_next;
+
+ protected:
+
+ void base_unlink()
+ {
+ // Connect the previous link with the next.
+ if (etl_previous != nullptr)
+ {
+ etl_previous->etl_next = etl_next;
+ }
+
+ // Connect the next link with the previous.
+ if (etl_next != nullptr)
+ {
+ etl_next->etl_previous = etl_previous;
+ }
+ }
+ };
+ }
+
+ //***************************************************************************
+ /// A bidirectional link.
+ //***************************************************************************
+ template <const size_t ID_, const size_t OPTION_ = etl::link_option::DEFAULT>
+ struct bidirectional_link
+ : public __private_intrusive_links__::bidirectional_link_base<bidirectional_link<ID_, OPTION_>, ID_, OPTION_>
+ {
+ void unlink()
+ {
+ this->base_unlink();
+ }
+ };
+
+ //******************************************************************
+ // Specialisation for auto unlinked option.
+ // When this link is destroyed it will automatically unlink itself.
+ //******************************************************************
+ template <const size_t ID_>
+ struct bidirectional_link<ID_, etl::link_option::AUTO>
+ : public __private_intrusive_links__::bidirectional_link_base<bidirectional_link<ID_, etl::link_option::AUTO>, ID_, etl::link_option::AUTO>
+ {
+ bidirectional_link()
+ {
+ this->clear();
+ }
+
+ ~bidirectional_link()
+ {
+ this->base_unlink();
+ }
+
+ void unlink()
+ {
+ this->base_unlink();
+ this->clear();
+ }
+ };
+
+ //******************************************************************
+ // Specialisation for checked unlink option.
+ // An error will be generated if the links are valid when the object
+ // is destroyed.
+ //******************************************************************
+ template <const size_t ID_>
+ struct bidirectional_link<ID_, etl::link_option::CHECKED>
+ : public __private_intrusive_links__::bidirectional_link_base<bidirectional_link<ID_, etl::link_option::CHECKED>, ID_, etl::link_option::CHECKED>
+ {
+ bidirectional_link()
+ {
+ this->clear();
+ }
+
+ ~bidirectional_link()
+ {
+ assert(this->etl_previous == nullptr);
+ assert(this->etl_next == nullptr);
+ }
+
+ void unlink()
+ {
+ this->base_unlink();
+ this->clear();
+ }
+ };
+
+ // Reference, Reference
+ template <typename TLink>
+ typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID, TLink::OPTION> >::value, void>::type
+ link(TLink& lhs, TLink& rhs)
+ {
+ lhs.etl_next = &rhs;
+ rhs.etl_previous = &lhs;
+ }
+
+ // Reference, Reference
+ template <typename TLink>
+ typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID, TLink::OPTION> >::value, void>::type
+ link_splice(TLink& lhs, TLink& rhs)
+ {
+ rhs.etl_next = lhs.etl_next;
+ rhs.etl_previous = &lhs;
+
+ if (lhs.etl_next != nullptr)
+ {
+ lhs.etl_next->etl_previous = &rhs;
+ }
+
+ lhs.etl_next = &rhs;
+ }
+
+ // Pointer, Pointer
+ template <typename TLink>
+ typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID, TLink::OPTION> >::value, void>::type
+ link(TLink* lhs, TLink* rhs)
+ {
+ if (lhs != nullptr)
+ {
+ lhs->etl_next = rhs;
+ }
+
+ if (rhs != nullptr)
+ {
+ rhs->etl_previous = lhs;
+ }
+ }
+
+ // Pointer, Pointer
+ template <typename TLink>
+ typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID, TLink::OPTION> >::value, void>::type
+ link_splice(TLink* lhs, TLink* rhs)
+ {
+ if (rhs != nullptr)
+ {
+ if (lhs != nullptr)
+ {
+ rhs->etl_next = lhs->etl_next;
+ }
+
+ rhs->etl_previous = lhs;
+ }
+
+ if (lhs != nullptr)
+ {
+ if (lhs->etl_next != nullptr)
+ {
+ lhs->etl_next->etl_previous = rhs;
+ }
+
+ lhs->etl_next = rhs;
+ }
+ }
+
+ // Reference, Pointer
+ template <typename TLink>
+ typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID, TLink::OPTION> >::value, void>::type
+ link(TLink& lhs, TLink* rhs)
+ {
+ lhs.etl_next = rhs;
+
+ if (rhs != nullptr)
+ {
+ rhs->etl_previous = &lhs;
+ }
+ }
+
+ // Reference, Pointer
+ template <typename TLink>
+ typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID, TLink::OPTION> >::value, void>::type
+ link_splice(TLink& lhs, TLink* rhs)
+ {
+ if (rhs != nullptr)
+ {
+ rhs->etl_next = lhs.etl_next;
+ rhs->etl_previous = &lhs;
+ }
+
+ if (lhs.etl_next != nullptr)
+ {
+ lhs.etl_next->etl_previous = rhs;
+ }
+
+ lhs.etl_next = rhs;
+ }
+
+ // Pointer, Reference
+ template <typename TLink>
+ typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID, TLink::OPTION> >::value, void>::type
+ link(TLink* lhs, TLink& rhs)
+ {
+ if (lhs != nullptr)
+ {
+ lhs->etl_next = &rhs;
+ }
+
+ rhs.etl_previous = lhs;
+ }
+
+ // Pointer, Reference
+ template <typename TLink>
+ typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID, TLink::OPTION> >::value, void>::type
+ link_splice(TLink* lhs, TLink& rhs)
+ {
+ if (lhs != nullptr)
+ {
+ rhs.etl_next = lhs->etl_next;
+ }
+
+ rhs.etl_previous = lhs;
+
+ if (lhs != nullptr)
+ {
+ if (lhs->etl_next != nullptr)
+ {
+ lhs->etl_next->etl_previous = &rhs;
+ }
+
+ lhs->etl_next = &rhs;
+ }
+ }
+
+ // Reference, Reference, Reference
+ template <typename TLink>
+ typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID, TLink::OPTION> >::value, void>::type
+ link_splice(TLink& lhs, TLink& first, TLink& last)
+ {
+ last.etl_next = lhs.etl_next;
+ first.etl_previous = &lhs;
+
+ if (last.etl_next != nullptr)
+ {
+ last.etl_next->etl_previous = &last;
+ }
+
+ lhs.etl_next = &first;
+ }
+
+ // Pointer, Reference, Reference
+ template <typename TLink>
+ typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID, TLink::OPTION> >::value, void>::type
+ link_splice(TLink* lhs, TLink& first, TLink& last)
+ {
+ if (lhs != nullptr)
+ {
+ last.etl_next = lhs->etl_next;
+ }
+ else
+ {
+ last.etl_next = nullptr;
+ }
+
+ first.etl_previous = lhs;
+
+ if (last.etl_next != nullptr)
+ {
+ last.etl_next->etl_previous = &last;
+ }
+
+ if (lhs != nullptr)
+ {
+ lhs->etl_next = &first;
+ }
+ }
+
+ // Reference
+ template <typename TLink>
+ typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID, TLink::OPTION> >::value, void>::type
+ unlink(TLink& node)
+ {
+ node.unlink();
+ }
+
+ // Reference Reference
+ template <typename TLink>
+ typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID, TLink::OPTION> >::value, void>::type
+ unlink(TLink& first, TLink& last)
+ {
+ if (&first == &last)
+ {
+ first.unlink();
+ }
+ else
+ {
+ if (last.etl_next != nullptr)
+ {
+ last.etl_next->etl_previous = first.etl_previous;
+ }
+
+ if (first.etl_previous != nullptr)
+ {
+ first.etl_previous->etl_next = last.etl_next;
+ }
+
+ if ((TLink::OPTION == etl::link_option::AUTO) ||
+ (int(TLink::OPTION) == etl::link_option::CHECKED))
+ {
+ first.etl_previous = nullptr;
+ last.etl_next = nullptr;
+ }
+ }
+ }
+
+ namespace __private_intrusive_links__
+ {
+ //***************************************************************************
+ /// A tree link base.
+ //***************************************************************************
+ template <typename TLink, const size_t ID_, const size_t OPTION_>
+ struct tree_link_base
+ {
+ enum
+ {
+ ID = ID_,
+ OPTION = OPTION_
+ };
+
+ void clear()
+ {
+ etl_parent = nullptr;
+ etl_left = nullptr;
+ etl_right = nullptr;
+ }
+
+ bool is_linked() const
+ {
+ return (etl_parent != nullptr) || (etl_left != nullptr) || (etl_right != nullptr);
+ }
+
+ TLink* etl_parent;
+ TLink* etl_left;
+ TLink* etl_right;
+ };
+ }
+
+ //***************************************************************************
+ /// A tree link.
+ //***************************************************************************
+ template <const size_t ID_, const size_t OPTION_ = etl::link_option::DEFAULT>
+ struct tree_link
+ : public __private_intrusive_links__::tree_link_base<tree_link<ID_, OPTION_>, ID_, OPTION_>
+ {
+ };
+
+ //******************************************************************
+ // There is no valid specialisation for auto link
+ //******************************************************************
+ template <const size_t ID_>
+ struct tree_link<ID_, etl::link_option::AUTO>
+ : public __private_intrusive_links__::tree_link_base<tree_link<ID_, etl::link_option::AUTO>, ID_, etl::link_option::AUTO>
+ {
+ tree_link()
+ {
+ this->clear();
+ }
+ };
+
+ //******************************************************************
+ // Specialisation for checked unlink option.
+ // An error will be generated if the links are valid when the object
+ // is destroyed.
+ //******************************************************************
+ template <const size_t ID_>
+ struct tree_link<ID_, etl::link_option::CHECKED>
+ : public __private_intrusive_links__::tree_link_base<tree_link<ID_, etl::link_option::CHECKED>, ID_, etl::link_option::CHECKED>
+ {
+ tree_link()
+ {
+ this->clear();
+ }
+
+ ~tree_link()
+ {
+ assert(this->etl_parent != nullptr);
+ assert(this->etl_left != nullptr);
+ assert(this->etl_right != nullptr);
+ }
+ };
+
+ // Reference, Reference
+ template <typename TLink>
+ typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID, TLink::OPTION> >::value, void>::type
+ link_left(TLink& parent, TLink& leaf)
+ {
+ parent.etl_left = &leaf;
+ leaf.etl_parent = &parent;
+ }
+
+ template <typename TLink>
+ typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID, TLink::OPTION> >::value, void>::type
+ link_right(TLink& parent, TLink& leaf)
+ {
+ parent.etl_right = &leaf;
+ leaf.etl_parent = &parent;
+ }
+
+ // Pointer, Pointer
+ template <typename TLink>
+ typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID, TLink::OPTION> >::value, void>::type
+ link_left(TLink* parent, TLink* leaf)
+ {
+ if (parent != nullptr)
+ {
+ parent->etl_left = leaf;
+ }
+
+ if (leaf != nullptr)
+ {
+ leaf->etl_parent = parent;
+ }
+ }
+
+ template <typename TLink>
+ typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID, TLink::OPTION> >::value, void>::type
+ link_right(TLink* parent, TLink* leaf)
+ {
+ if (parent != nullptr)
+ {
+ parent->etl_right = leaf;
+ }
+
+ if (leaf != nullptr)
+ {
+ leaf->etl_parent = parent;
+ }
+ }
+
+ // Reference, Pointer
+ template <typename TLink>
+ typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID, TLink::OPTION> >::value, void>::type
+ link_left(TLink& parent, TLink* leaf)
+ {
+ parent.etl_left = leaf;
+
+ if (leaf != nullptr)
+ {
+ leaf->etl_parent = &parent;
+ }
+ }
+
+ template <typename TLink>
+ typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID, TLink::OPTION> >::value, void>::type
+ link_right(TLink& parent, TLink* leaf)
+ {
+ parent.etl_right = leaf;
+
+ if (leaf != nullptr)
+ {
+ leaf->etl_parent = &parent;
+ }
+ }
+
+ // Pointer, Reference
+ template <typename TLink>
+ typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID, TLink::OPTION> >::value, void>::type
+ link_left(TLink* parent, TLink& leaf)
+ {
+ if (parent != nullptr)
+ {
+ parent->etl_left = &leaf;
+ }
+
+ leaf.etl_parent = parent;
+ }
+
+ template <typename TLink>
+ typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID, TLink::OPTION> >::value, void>::type
+ link_right(TLink* parent, TLink& leaf)
+ {
+ if (parent != nullptr)
+ {
+ parent->etl_right = &leaf;
+ }
+
+ leaf.etl_parent = parent;
+ }
+}
+
+#undef ETL_FILE
+#endif
diff --git a/lib/etl/intrusive_list.h b/lib/etl/intrusive_list.h
new file mode 100644
index 0000000..c4050db
--- /dev/null
+++ b/lib/etl/intrusive_list.h
@@ -0,0 +1,1213 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_INTRUSIVE_LIST__
+#define __ETL_INTRUSIVE_LIST__
+
+#include "platform.h"
+
+#ifdef ETL_COMPILER_MICROSOFT
+#undef min
+#endif
+
+#include <iterator>
+#include <algorithm>
+#include <functional>
+#include <stddef.h>
+
+#include "nullptr.h"
+#include "type_traits.h"
+#include "exception.h"
+#include "error_handler.h"
+#include "intrusive_links.h"
+#include "static_assert.h"
+#include "algorithm.h"
+
+#undef ETL_FILE
+#define ETL_FILE "21"
+
+namespace etl
+{
+ //***************************************************************************
+ /// Exception for the intrusive_list.
+ ///\ingroup intrusive_list
+ //***************************************************************************
+ class intrusive_list_exception : public exception
+ {
+ public:
+
+ intrusive_list_exception(string_type what, string_type file_name, numeric_type line_number)
+ : exception(what, file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// Empty exception for the intrusive_list.
+ ///\ingroup intrusive_list
+ //***************************************************************************
+ class intrusive_list_empty : public intrusive_list_exception
+ {
+ public:
+
+ intrusive_list_empty(string_type file_name, numeric_type line_number)
+ : intrusive_list_exception(ETL_ERROR_TEXT("intrusive_list:empty", ETL_FILE"A"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// Iterator exception for the intrusive_list.
+ ///\ingroup intrusive_list
+ //***************************************************************************
+ class intrusive_list_iterator_exception : public intrusive_list_exception
+ {
+ public:
+
+ intrusive_list_iterator_exception(string_type file_name, numeric_type line_number)
+ : intrusive_list_exception(ETL_ERROR_TEXT("intrusive_list:iterator", ETL_FILE"B"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// Unsorted exception for the intrusive_list.
+ ///\ingroup intrusive_list
+ //***************************************************************************
+ class intrusive_list_unsorted : public intrusive_list_exception
+ {
+ public:
+
+ intrusive_list_unsorted(string_type file_name, numeric_type line_number)
+ : intrusive_list_exception(ETL_ERROR_TEXT("intrusive_list:unsorted", ETL_FILE"C"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// An intrusive list.
+ ///\ingroup intrusive_list
+ ///\note TLink must be a base of TValue.
+ //***************************************************************************
+ template <typename TValue, typename TLink = etl::bidirectional_link<0> >
+ class intrusive_list
+ {
+ public:
+
+ enum
+ {
+ // The count option is based on the type of link.
+ COUNT_OPTION = ((TLink::OPTION == etl::link_option::AUTO) ||
+ (TLink::OPTION == etl::link_option::CHECKED)) ? etl::count_option::SLOW_COUNT : etl::count_option::FAST_COUNT
+ };
+
+ typedef intrusive_list<TValue, TLink> list_type;
+
+ // Node typedef.
+ typedef TLink link_type;
+
+ // STL style typedefs.
+ typedef TValue value_type;
+ typedef value_type* pointer;
+ typedef const value_type* const_pointer;
+ typedef value_type& reference;
+ typedef const value_type& const_reference;
+ typedef size_t size_type;
+
+ //*************************************************************************
+ /// iterator.
+ //*************************************************************************
+ class iterator : public std::iterator<std::bidirectional_iterator_tag, value_type>
+ {
+ public:
+
+ friend class intrusive_list;
+
+ iterator()
+ : p_value(nullptr)
+ {
+ }
+
+ iterator(value_type& value)
+ : p_value(&value)
+ {
+ }
+
+ iterator(const iterator& other)
+ : p_value(other.p_value)
+ {
+ }
+
+ iterator& operator ++()
+ {
+ // Read the appropriate 'etl_next'.
+ p_value = static_cast<value_type*>(p_value->link_type::etl_next);
+ return *this;
+ }
+
+ iterator operator ++(int)
+ {
+ iterator temp(*this);
+ // Read the appropriate 'etl_next'.
+ p_value = static_cast<value_type*>(p_value->link_type::etl_next);
+ return temp;
+ }
+
+ iterator& operator --()
+ {
+ // Read the appropriate 'etl_previous'.
+ p_value = static_cast<value_type*>(p_value->link_type::etl_previous);
+ return *this;
+ }
+
+ iterator operator --(int)
+ {
+ iterator temp(*this);
+ // Read the appropriate 'etl_previous'.
+ p_value = static_cast<value_type*>(p_value->link_type::etl_previous);
+ return temp;
+ }
+
+ iterator operator =(const iterator& other)
+ {
+ p_value = other.p_value;
+ return *this;
+ }
+
+ reference operator *()
+ {
+ return *p_value;
+ }
+
+ const_reference operator *() const
+ {
+ return *p_value;
+ }
+
+ pointer operator &()
+ {
+ return p_value;
+ }
+
+ const_pointer operator &() const
+ {
+ return p_value;
+ }
+
+ pointer operator ->()
+ {
+ return p_value;
+ }
+
+ const_pointer operator ->() const
+ {
+ return p_value;
+ }
+
+ friend bool operator == (const iterator& lhs, const iterator& rhs)
+ {
+ return lhs.p_value == rhs.p_value;
+ }
+
+ friend bool operator != (const iterator& lhs, const iterator& rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+ private:
+
+ value_type* p_value;
+ };
+
+ //*************************************************************************
+ /// const_iterator
+ //*************************************************************************
+ class const_iterator : public std::iterator<std::bidirectional_iterator_tag, const value_type>
+ {
+ public:
+
+ friend class intrusive_list;
+
+ const_iterator()
+ : p_value(nullptr)
+ {
+ }
+
+ const_iterator(const value_type& value)
+ : p_value(&value)
+ {
+ }
+
+ const_iterator(const typename intrusive_list::iterator& other)
+ : p_value(other.p_value)
+ {
+ }
+
+ const_iterator(const const_iterator& other)
+ : p_value(other.p_value)
+ {
+ }
+
+ const_iterator& operator ++()
+ {
+ // Read the appropriate 'etl_next'.
+ p_value = static_cast<value_type*>(p_value->link_type::etl_next);
+ return *this;
+ }
+
+ const_iterator operator ++(int)
+ {
+ const_iterator temp(*this);
+ // Read the appropriate 'etl_next'.
+ p_value = static_cast<value_type*>(p_value->link_type::etl_next);
+ return temp;
+ }
+
+ const_iterator& operator --()
+ {
+ // Read the appropriate 'etl_previous'.
+ p_value = static_cast<value_type*>(p_value->link_type::etl_previous);
+ return *this;
+ }
+
+ const_iterator operator --(int)
+ {
+ const_iterator temp(*this);
+ // Read the appropriate 'etl_previous'.
+ p_value = static_cast<value_type*>(p_value->link_type::etl_previous);
+ return temp;
+ }
+
+ const_iterator operator =(const const_iterator& other)
+ {
+ p_value = other.p_value;
+ return *this;
+ }
+
+ const_reference operator *() const
+ {
+ return *p_value;
+ }
+
+ const_pointer operator &() const
+ {
+ return p_value;
+ }
+
+ const_pointer operator ->() const
+ {
+ return p_value;
+ }
+
+ friend bool operator == (const const_iterator& lhs, const const_iterator& rhs)
+ {
+ return lhs.p_value == rhs.p_value;
+ }
+
+ friend bool operator != (const const_iterator& lhs, const const_iterator& rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+ private:
+
+ const value_type* p_value;
+ };
+
+ typedef typename std::iterator_traits<iterator>::difference_type difference_type;
+
+ //*************************************************************************
+ /// Constructor.
+ //*************************************************************************
+ intrusive_list()
+ {
+ initialise();
+ }
+
+ //*************************************************************************
+ /// Constructor from range
+ //*************************************************************************
+ template <typename TIterator>
+ intrusive_list(TIterator first, TIterator last)
+ {
+ assign(first, last);
+ }
+
+ //*************************************************************************
+ /// Gets the beginning of the intrusive_list.
+ //*************************************************************************
+ iterator begin()
+ {
+ return iterator(static_cast<value_type&>(*get_head()));
+ }
+
+ //*************************************************************************
+ /// Gets the beginning of the intrusive_list.
+ //*************************************************************************
+ const_iterator begin() const
+ {
+ return const_iterator(static_cast<const value_type&>(*get_head()));
+ }
+
+ //*************************************************************************
+ /// Gets the beginning of the intrusive_list.
+ //*************************************************************************
+ const_iterator cbegin() const
+ {
+ return const_iterator(static_cast<const value_type&>(*get_head()));
+ }
+
+ //*************************************************************************
+ /// Gets the end of the intrusive_list.
+ //*************************************************************************
+ iterator end()
+ {
+ return iterator(static_cast<value_type&>(terminal_link));
+ }
+
+ //*************************************************************************
+ /// Gets the end of the intrusive_list.
+ //*************************************************************************
+ const_iterator end() const
+ {
+ return const_iterator(static_cast<const value_type&>(terminal_link));
+ }
+
+ //*************************************************************************
+ /// Gets the end of the intrusive_list.
+ //*************************************************************************
+ const_iterator cend() const
+ {
+ return const_iterator(static_cast<const value_type&>(terminal_link));
+ }
+
+ //*************************************************************************
+ /// Clears the intrusive_list.
+ //*************************************************************************
+ void clear()
+ {
+ initialise();
+ }
+
+ //*************************************************************************
+ /// Gets a reference to the first element.
+ //*************************************************************************
+ reference front()
+ {
+ return *static_cast<value_type*>(get_head());
+ }
+
+ //*************************************************************************
+ /// Gets a const reference to the first element.
+ //*************************************************************************
+ const_reference front() const
+ {
+ return *static_cast<const value_type*>(get_head());;
+ }
+
+ //*************************************************************************
+ /// Gets a reference to the last element.
+ //*************************************************************************
+ reference back()
+ {
+ return *static_cast<value_type*>(get_tail());
+ }
+
+ //*************************************************************************
+ /// Gets a const reference to the last element.
+ //*************************************************************************
+ const_reference back() const
+ {
+ return *static_cast<const value_type*>(get_tail());;
+ }
+
+ //*************************************************************************
+ /// Assigns a range of values to the intrusive_list.
+ /// If ETL_THROW_EXCEPTIONS & _DEBUG are defined emits a
+ /// intrusive_list_iterator_exception if the iterators are reversed.
+ //*************************************************************************
+ template <typename TIterator>
+ void assign(TIterator first, TIterator last)
+ {
+#ifdef _DEBUG
+ difference_type count = std::distance(first, last);
+ ETL_ASSERT(count >= 0, ETL_ERROR(intrusive_list_iterator_exception));
+#endif
+
+ initialise();
+
+ link_type* p_last_link = &terminal_link;
+
+ // Add all of the elements.
+ while (first != last)
+ {
+ link_type& link = *first++;
+ etl::link_splice<link_type>(p_last_link, link);
+ p_last_link = &link;
+ ++current_size;
+ }
+ }
+
+ //*************************************************************************
+ /// Pushes a value to the front of the intrusive_list.
+ //*************************************************************************
+ void push_front(value_type& value)
+ {
+ insert_link(terminal_link, value);
+ }
+
+ //*************************************************************************
+ /// Removes a value from the front of the intrusive_list.
+ //*************************************************************************
+ void pop_front()
+ {
+#if defined(ETL_CHECK_PUSH_POP)
+ ETL_ASSERT(!empty(), ETL_ERROR(intrusive_list_empty));
+#endif
+ remove_link(get_head());
+ }
+
+ //*************************************************************************
+ /// Pushes a value to the back of the intrusive_list.
+ //*************************************************************************
+ void push_back(value_type& value)
+ {
+ insert_link(terminal_link.link_type::etl_previous, value);
+ }
+
+ //*************************************************************************
+ /// Removes a value from the back of the intrusive_list.
+ //*************************************************************************
+ void pop_back()
+ {
+#if defined(ETL_CHECK_PUSH_POP)
+ ETL_ASSERT(!empty(), ETL_ERROR(intrusive_list_empty));
+#endif
+ remove_link(get_tail());
+ }
+
+ //*************************************************************************
+ /// Reverses the list.
+ //*************************************************************************
+ void reverse()
+ {
+ if (is_trivial_list())
+ {
+ return;
+ }
+
+ link_type* pnode = terminal_link.etl_next;
+
+ while (pnode != &terminal_link)
+ {
+ pnode->reverse();
+ pnode = pnode->etl_previous; // Now we've reversed it, we must go to the previous node.
+ }
+
+ // Terminal node.
+ pnode->reverse();
+ }
+
+ //*************************************************************************
+ /// Inserts a value to the intrusive_list before the specified position.
+ /// Checks that the value is unlinked if CHECKED
+ //*************************************************************************
+ iterator insert(iterator position, value_type& value)
+ {
+ if (TLink::OPTION == etl::link_option::CHECKED)
+ {
+ ETL_ASSERT(!value.TLink::is_linked(), ETL_ERROR(etl::not_unlinked_exception));
+ }
+
+ insert_link(position.p_value->link_type::etl_previous, value);
+ return iterator(value);
+ }
+
+ //*************************************************************************
+ /// Inserts a range of values to the intrusive_list after the specified position.
+ /// Checks that the values are unlinked if CHECKED.
+ //*************************************************************************
+ template <typename TIterator>
+ void insert(iterator position, TIterator first, TIterator last)
+ {
+ while (first != last)
+ {
+ if (TLink::OPTION == etl::link_option::CHECKED)
+ {
+ ETL_ASSERT(!position.p_value->TLink::is_linked(), ETL_ERROR(etl::not_unlinked_exception));
+ }
+
+ // Set up the next free link.
+ insert_link(*position.p_value->link_type::etl_previous, *first++);
+ }
+ }
+
+ //*************************************************************************
+ /// Erases the value at the specified position.
+ //*************************************************************************
+ iterator erase(iterator position)
+ {
+ iterator next(position);
+ ++next;
+
+ remove_link(*position.p_value);
+
+ return next;
+ }
+
+ //*************************************************************************
+ /// Erases a range of elements.
+ /// Clears the links after erasing if AUTO or CHECKED.
+ //*************************************************************************
+ iterator erase(iterator first, iterator last)
+ {
+ link_type* p_first = first.p_value;
+ link_type* p_last = last.p_value;
+
+ // Join the ends.
+ etl::link<link_type>(p_first->etl_previous, p_last);
+
+ if (COUNT_OPTION == etl::count_option::FAST_COUNT)
+ {
+ current_size -= std::distance(first, last);
+ }
+
+ if ((TLink::OPTION == etl::link_option::AUTO) ||
+ (TLink::OPTION == etl::link_option::CHECKED))
+ {
+ // Clear the ones in between.
+ link_type* p_next;
+
+ while (p_first != p_last)
+ {
+ // One less.
+ --current_size;
+
+ p_next = p_first->etl_next; // Remember the next link.
+ p_first->TLink::clear(); // Clear the link.
+ p_first = p_next; // Move to the next link.
+ }
+ }
+
+ if (p_last == &terminal_link)
+ {
+ return end();
+ }
+ else
+ {
+ return iterator(*static_cast<value_type*>(p_last));
+ }
+ }
+
+ //*************************************************************************
+ /// Removes all but the one element from every consecutive group of equal
+ /// elements in the container.
+ //*************************************************************************
+ template <typename TIsEqual>
+ void unique(TIsEqual isEqual)
+ {
+ if (empty())
+ {
+ return;
+ }
+
+ iterator i_item = begin();
+ ++i_item;
+ iterator i_previous = begin();
+
+ while (i_item != end())
+ {
+ if (isEqual(*i_previous, *i_item))
+ {
+ i_item = erase(i_item);
+ }
+ else
+ {
+ i_previous = i_item;
+ ++i_item;
+ }
+ }
+ }
+
+ //*************************************************************************
+ /// Sort using in-place merge sort algorithm.
+ //*************************************************************************
+ void sort()
+ {
+ sort(std::less<value_type>());
+ }
+
+ //*************************************************************************
+ /// Sort using in-place merge sort algorithm.
+ /// Uses a supplied predicate function or functor.
+ /// This is not my algorithm. I got it off the web somewhere.
+ //*************************************************************************
+ template <typename TCompare>
+ void sort(TCompare compare)
+ {
+ iterator i_left;
+ iterator i_right;
+ iterator i_node;
+ iterator i_head;
+ iterator i_tail;
+ int list_size = 1;
+ int number_of_merges;
+ int left_size;
+ int right_size;
+
+ if (is_trivial_list())
+ {
+ return;
+ }
+
+ while (true)
+ {
+ i_left = begin();
+ i_head = end();
+ i_tail = end();
+
+ number_of_merges = 0; // Count the number of merges we do in this pass.
+
+ while (i_left != end())
+ {
+ ++number_of_merges; // There exists a merge to be done.
+ i_right = i_left;
+ left_size = 0;
+
+ // Step 'list_size' places along from left
+ for (int i = 0; i < list_size; ++i)
+ {
+ ++left_size;
+ ++i_right;
+
+ if (i_right == end())
+ {
+ break;
+ }
+ }
+
+ // If right hasn't fallen off end, we have two lists to merge.
+ right_size = list_size;
+
+ // Now we have two lists. Merge them.
+ while (left_size > 0 || (right_size > 0 && i_right != end()))
+ {
+ // Decide whether the next node of merge comes from left or right.
+ if (left_size == 0)
+ {
+ // Left is empty. The node must come from right.
+ i_node = i_right++;
+ --right_size;
+ }
+ else if (right_size == 0 || i_right == end())
+ {
+ // Right is empty. The node must come from left.
+ i_node = i_left++;
+ --left_size;
+ }
+ else if (compare(*i_left, *i_right))
+ {
+ // First node of left is lower or same. The node must come from left.
+ i_node = i_left++;
+ --left_size;
+ }
+ else
+ {
+ // First node of right is lower. The node must come from right.
+ i_node = i_right;
+ ++i_right;
+ --right_size;
+ }
+
+ // Add the next node to the merged head.
+ if (i_head == end())
+ {
+ etl::link<link_type>(i_head.p_value, i_node.p_value);
+ i_head = i_node;
+ i_tail = i_node;
+ }
+ else
+ {
+ etl::link<link_type>(i_tail.p_value, i_node.p_value);
+ i_tail = i_node;
+ }
+
+ etl::link<link_type>(i_tail.p_value, terminal_link);
+ }
+
+ // Now left has stepped `list_size' places along, and right has too.
+ i_left = i_right;
+ }
+
+ // If we have done only one merge, we're finished.
+ if (number_of_merges <= 1) // Allow for number_of_merges == 0, the empty head case
+ {
+ return;
+ }
+
+ // Otherwise repeat, merging lists twice the size
+ list_size *= 2;
+ }
+ }
+
+ //*************************************************************************
+ // Removes the values specified.
+ //*************************************************************************
+ void remove(const_reference value)
+ {
+ iterator i_item = begin();
+
+ while (i_item != end())
+ {
+ if (*i_item == value)
+ {
+ i_item = erase(i_item);
+ }
+ else
+ {
+ ++i_item;
+ }
+ }
+ }
+
+ //*************************************************************************
+ /// Removes according to a predicate.
+ //*************************************************************************
+ template <typename TPredicate>
+ void remove_if(TPredicate predicate)
+ {
+ iterator i_item = begin();
+
+ while (i_item != end())
+ {
+ if (predicate(*i_item))
+ {
+ i_item = erase(i_item);
+ }
+ else
+ {
+ ++i_item;
+ }
+ }
+ }
+
+ //*************************************************************************
+ /// Returns true if the list has no elements.
+ //*************************************************************************
+ bool empty() const
+ {
+ return (terminal_link.link_type::etl_next == &terminal_link);
+ }
+
+ //*************************************************************************
+ /// Returns the number of elements.
+ //*************************************************************************
+ size_t size() const
+ {
+ if (COUNT_OPTION == etl::count_option::SLOW_COUNT)
+ {
+ return std::distance(cbegin(), cend());
+ }
+ else
+ {
+ return current_size.get_count();
+ }
+ }
+
+ //*************************************************************************
+ /// Splice another list into this one.
+ //*************************************************************************
+ void splice(iterator position, list_type& list)
+ {
+ // No point splicing to ourself!
+ if (&list != this)
+ {
+ if (!list.empty())
+ {
+ link_type& first = *list.get_head();
+ link_type& last = *list.get_tail();
+
+ if (COUNT_OPTION == etl::count_option::FAST_COUNT)
+ {
+ if (&list != this)
+ {
+ current_size += list.size();
+ }
+ }
+
+ link_type& after = *position.p_value;
+ link_type& before = *after.etl_previous;
+
+ etl::link<link_type>(before, first);
+ etl::link<link_type>(last, after);
+
+ list.clear();
+ }
+ }
+ }
+
+ //*************************************************************************
+ /// Splice an element from another list into this one.
+ //*************************************************************************
+ void splice(iterator position, list_type& list, iterator isource)
+ {
+ link_type& before = *position.p_value->link_type::etl_previous;
+
+ etl::unlink<link_type>(*isource.p_value);
+ etl::link_splice<link_type>(before, *isource.p_value);
+
+ if (COUNT_OPTION == etl::count_option::FAST_COUNT)
+ {
+ if (&list != this)
+ {
+ ++current_size;
+ --list.current_size;
+ }
+ }
+ }
+
+ //*************************************************************************
+ /// Splice a range of elements from another list into this one.
+ //*************************************************************************
+ void splice(iterator position, list_type& list, iterator begin_, iterator end_)
+ {
+ if (!list.empty())
+ {
+ if (COUNT_OPTION == etl::count_option::FAST_COUNT)
+ {
+ if (&list != this)
+ {
+ size_t n = std::distance(begin_, end_);
+ current_size += n;
+ list.current_size -= n;
+ }
+ }
+
+ link_type& first = *begin_.p_value;
+ link_type& last = *end_.p_value->link_type::etl_previous;
+
+ // Unlink from the source list.
+ etl::unlink(first, last);
+
+ // Fix our links.
+ link_type& before = *position.p_value->link_type::etl_previous;
+
+ etl::link_splice<link_type>(before, first, last);
+ }
+ }
+
+ //*************************************************************************
+ /// Merge another list into this one. Both lists should be sorted.
+ //*************************************************************************
+ void merge(list_type& list)
+ {
+ merge(list, std::less<value_type>());
+ }
+
+ //*************************************************************************
+ /// Merge another list into this one. Both lists should be sorted.
+ //*************************************************************************
+ template <typename TCompare>
+ void merge(list_type& list, TCompare compare)
+ {
+ if (!list.empty())
+ {
+#if _DEBUG
+ ETL_ASSERT(etl::is_sorted(list.begin(), list.end(), compare), ETL_ERROR(intrusive_list_unsorted));
+ ETL_ASSERT(etl::is_sorted(begin(), end(), compare), ETL_ERROR(intrusive_list_unsorted));
+#endif
+
+ value_type* other_begin = static_cast<value_type*>(list.get_head());
+ value_type* other_end = static_cast<value_type*>(&list.terminal_link);
+
+ value_type* begin = static_cast<value_type*>(get_head());
+ value_type* end = static_cast<value_type*>(&terminal_link);
+
+ while ((begin != end) && (other_begin != other_end))
+ {
+ // Find the place to insert.
+ while ((begin != end) && !(compare(*other_begin, *begin)))
+ {
+ begin = static_cast<value_type*>(begin->link_type::etl_next);
+ }
+
+ // Insert.
+ if (begin != end)
+ {
+ while ((other_begin != other_end) && (compare(*other_begin, *begin)))
+ {
+ value_type* value = other_begin;
+ other_begin = static_cast<value_type*>(other_begin->link_type::etl_next);
+ etl::link_splice<link_type>(*begin->link_type::etl_previous, *value);
+ }
+ }
+ }
+
+ // Any left over?
+ if ((begin == end) && (other_begin != other_end))
+ {
+ etl::link_splice<link_type>(*get_tail(), *other_begin, *other_end->link_type::etl_previous);
+ }
+
+
+ if (COUNT_OPTION == etl::count_option::FAST_COUNT)
+ {
+ current_size += list.size();
+ }
+
+ list.clear();
+ }
+ }
+
+ private:
+
+ /// The link that acts as the intrusive_list start & end.
+ link_type terminal_link;
+
+ //*************************************************************************
+ /// Counter type based on count option.
+ //*************************************************************************
+ template <const size_t OPTION, bool dummy = true>
+ class counter_type
+ {
+ };
+
+ //*************************************************************************
+ /// Slow type.
+ //*************************************************************************
+ template <bool dummy>
+ class counter_type<etl::count_option::SLOW_COUNT, dummy>
+ {
+ public:
+
+ counter_type& operator ++()
+ {
+ return *this;
+ }
+
+ counter_type& operator --()
+ {
+ return *this;
+ }
+
+ counter_type& operator =(size_t new_count)
+ {
+ return *this;
+ }
+
+ counter_type& operator +=(size_t diff)
+ {
+ return *this;
+ }
+
+ counter_type& operator -=(size_t diff)
+ {
+ return *this;
+ }
+
+ size_t get_count() const
+ {
+ return 0;
+ }
+ };
+
+ //*************************************************************************
+ /// Fast type.
+ //*************************************************************************
+ template <bool dummy>
+ class counter_type<etl::count_option::FAST_COUNT, dummy>
+ {
+ public:
+
+ counter_type()
+ : count(0)
+ {
+ }
+
+ counter_type& operator ++()
+ {
+ ++count;
+ return *this;
+ }
+
+ counter_type& operator --()
+ {
+ --count;
+ return *this;
+ }
+
+ counter_type& operator =(size_t new_count)
+ {
+ count = new_count;
+ return *this;
+ }
+
+ counter_type& operator +=(size_t diff)
+ {
+ count += diff;
+ return *this;
+ }
+
+ counter_type& operator -=(size_t diff)
+ {
+ count -= diff;
+ return *this;
+ }
+
+ size_t get_count() const
+ {
+ return count;
+ }
+
+ size_t count;
+ };
+
+ counter_type<COUNT_OPTION> current_size; ///< Counts the number of elements in the list.
+
+ //*************************************************************************
+ /// Is the intrusive_list a trivial length?
+ //*************************************************************************
+ bool is_trivial_list() const
+ {
+ return (terminal_link.link_type::etl_next == &terminal_link) || (terminal_link.link_type::etl_next->etl_next == &terminal_link);
+ }
+
+ //*************************************************************************
+ /// Insert a link.
+ //*************************************************************************
+ void insert_link(link_type& previous, link_type& new_link)
+ {
+ // Connect to the intrusive_list.
+ etl::link_splice<link_type>(previous, new_link);
+ ++current_size;
+ }
+
+ //*************************************************************************
+ /// Insert a link.
+ //*************************************************************************
+ void insert_link(link_type* previous, link_type& new_link)
+ {
+ // Connect to the intrusive_list.
+ etl::link_splice<link_type>(previous, new_link);
+ ++current_size;
+ }
+
+ //*************************************************************************
+ /// Insert a link.
+ //*************************************************************************
+ void insert_link(link_type& previous, link_type* new_link)
+ {
+ // Connect to the intrusive_list.
+ etl::link_splice<link_type>(previous, new_link);
+ ++current_size;
+ }
+
+ //*************************************************************************
+ /// Insert a link.
+ //*************************************************************************
+ void insert_link(link_type* previous, link_type* new_link)
+ {
+ // Connect to the intrusive_list.
+ etl::link_splice<link_type>(previous, new_link);
+ ++current_size;
+ }
+
+ //*************************************************************************
+ /// Remove a link.
+ //*************************************************************************
+ void remove_link(link_type& link)
+ {
+ etl::unlink<link_type>(link);
+ --current_size;
+ }
+
+ //*************************************************************************
+ /// Remove a link.
+ //*************************************************************************
+ void remove_link(link_type* link)
+ {
+ etl::unlink<link_type>(*link);
+ --current_size;
+ }
+
+ //*************************************************************************
+ /// Get the head link.
+ //*************************************************************************
+ link_type* get_head()
+ {
+ return terminal_link.etl_next;
+ }
+
+ //*************************************************************************
+ /// Get the head link.
+ //*************************************************************************
+ const link_type* get_head() const
+ {
+ return terminal_link.etl_next;
+ }
+
+ //*************************************************************************
+ /// Get the tail link.
+ //*************************************************************************
+ link_type* get_tail()
+ {
+ return terminal_link.etl_previous;
+ }
+
+ //*************************************************************************
+ /// Get the tail link.
+ //*************************************************************************
+ const link_type* get_tail() const
+ {
+ return terminal_link.etl_previous;
+ }
+
+ //*************************************************************************
+ /// Initialise the intrusive_list.
+ //*************************************************************************
+ void initialise()
+ {
+ etl::link(terminal_link, terminal_link);
+ current_size = 0;
+ }
+
+ // Disabled.
+ intrusive_list(const intrusive_list& other);
+ intrusive_list& operator = (const intrusive_list& rhs);
+ };
+}
+
+#ifdef ETL_COMPILER_MICROSOFT
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#undef ETL_FILE
+
+#endif
diff --git a/lib/etl/io_port.h b/lib/etl/io_port.h
new file mode 100644
index 0000000..c442796
--- /dev/null
+++ b/lib/etl/io_port.h
@@ -0,0 +1,493 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_IO_PORT__
+#define __ETL_IO_PORT__
+
+///\defgroup io_port io port
+/// IO port access
+///\ingroup utilities
+
+#include <stdint.h>
+
+#include "nullptr.h"
+#include "parameter_type.h"
+
+namespace etl
+{
+ //***************************************************************************
+ /// Read write port.
+ //***************************************************************************
+ template <typename T, uintptr_t ADDRESS = 0>
+ class io_port_rw
+ {
+ private:
+
+ typedef volatile T* pointer_t;
+ typedef typename etl::parameter_type<T>::type parameter_t;
+
+ public:
+
+ class iterator
+ {
+ typedef io_port_rw<T, ADDRESS> iop_t;
+
+ public:
+
+ iterator(iop_t& iop)
+ : p_iop(&iop)
+ {
+ }
+
+ iterator(const iterator& other)
+ : p_iop(other)
+ {
+ }
+
+ iterator& operator =(const iterator& other)
+ {
+ p_iop = other.p_iop;
+ return *this;
+ }
+
+ iop_t& operator *()
+ {
+ return *p_iop;
+ }
+
+ const iop_t& operator *() const
+ {
+ return *p_iop;
+ }
+
+ iterator& operator ++()
+ {
+ return *this;
+ }
+
+ iterator operator ++(int)
+ {
+ return *this;
+ }
+
+ iterator& operator --()
+ {
+ return *this;
+ }
+
+ iterator operator --(int)
+ {
+ return *this;
+ }
+
+ private:
+
+ iop_t* p_iop;
+ };
+
+ /// Read.
+ operator T() volatile const
+ {
+ return *reinterpret_cast<pointer_t>(ADDRESS);
+ }
+
+ /// Read.
+ T value() volatile const
+ {
+ return *reinterpret_cast<pointer_t>(ADDRESS);
+ }
+
+ /// Write.
+ io_port_rw& operator =(parameter_t value)
+ {
+ *reinterpret_cast<pointer_t>(ADDRESS) = value;
+ return *this;
+ }
+
+ /// Get the IO port address.
+ pointer_t get_address()
+ {
+ return reinterpret_cast<pointer_t>(ADDRESS);
+ }
+
+ /// Get the iterator.
+ iterator get_iterator()
+ {
+ return iterator(*this);
+ }
+ };
+
+ //***************************************************************************
+ /// Read only port.
+ //***************************************************************************
+ template <typename T, uintptr_t ADDRESS = 0>
+ class io_port_ro
+ {
+ private:
+
+ typedef volatile const T* pointer_t;
+ typedef typename etl::parameter_type<T>::type parameter_t;
+
+ /// Write disabled.
+ void operator =(parameter_t value);
+
+ public:
+
+ /// Read.
+ operator T() volatile const
+ {
+ return *reinterpret_cast<pointer_t>(ADDRESS);
+ }
+
+ /// Read.
+ T value() volatile const
+ {
+ return *reinterpret_cast<pointer_t>(ADDRESS);
+ }
+
+ /// Get the IO port address.
+ pointer_t get_address()
+ {
+ return reinterpret_cast<pointer_t>(ADDRESS);
+ }
+ };
+
+ //***************************************************************************
+ /// Write only port.
+ //***************************************************************************
+ template <typename T, uintptr_t ADDRESS = 0>
+ class io_port_wo
+ {
+ private:
+
+ typedef T* pointer_t;
+ typedef typename etl::parameter_type<T>::type parameter_t;
+
+ /// Read disabled.
+ operator T() volatile const;
+
+ public:
+
+ /// Write.
+ void operator =(parameter_t value)
+ {
+ *reinterpret_cast<pointer_t>(ADDRESS) = value;
+ }
+
+ /// Get the IO port address.
+ pointer_t get_address()
+ {
+ return reinterpret_cast<pointer_t>(ADDRESS);
+ }
+ };
+
+ //***************************************************************************
+ /// Write only port with shadow register.
+ //***************************************************************************
+ template <typename T, uintptr_t ADDRESS = 0>
+ class io_port_wos
+ {
+ private:
+
+ typedef T* pointer_t;
+ typedef typename etl::parameter_type<T>::type parameter_t;
+
+ public:
+
+ /// Read.
+ operator T() const
+ {
+ return shadow_value;
+ }
+
+ /// Read.
+ T value() const
+ {
+ return shadow_value;
+ }
+
+ /// Write.
+ io_port_wos& operator =(parameter_t value)
+ {
+ shadow_value = value;
+ *reinterpret_cast<pointer_t>(ADDRESS) = shadow_value;
+ return *this;
+ }
+
+ /// Get the IO port address.
+ pointer_t get_address()
+ {
+ return reinterpret_cast<pointer_t>(ADDRESS);
+ }
+
+ private:
+
+ T shadow_value;
+ };
+
+ //***************************************************************************
+ /// Read write port.
+ /// Specialisation for dynamic addresses.
+ //***************************************************************************
+ template <typename T>
+ class io_port_rw<T, 0>
+ {
+ private:
+
+ typedef volatile T* pointer_t;
+ typedef typename etl::parameter_type<T>::type parameter_t;
+
+ public:
+
+ // Default constructor.
+ io_port_rw()
+ : address(nullptr)
+ {
+ }
+
+ // Constructor.
+ io_port_rw(uint8_t* address_)
+ : address(reinterpret_cast<pointer_t>(address_))
+ {
+ }
+
+ /// Set the IO port address.
+ void set_address(uintptr_t address_)
+ {
+ address = reinterpret_cast<pointer_t>(address_);
+ }
+
+ /// Get the IO port address.
+ pointer_t get_address()
+ {
+ return address;
+ }
+
+ /// Read.
+ operator T() volatile const
+ {
+ return *address;
+ }
+
+ /// Read.
+ T value() volatile const
+ {
+ return *address;
+ }
+
+ /// Write.
+ io_port_rw& operator =(parameter_t value)
+ {
+ *address = value;
+ return *this;
+ }
+
+ private:
+
+ pointer_t address;
+ };
+
+ //***************************************************************************
+ /// Read only port.
+ /// Specialisation for dynamic addresses.
+ //***************************************************************************
+ template <typename T>
+ class io_port_ro<T, 0>
+ {
+ private:
+
+ typedef volatile const T* pointer_t;
+
+ public:
+
+ // Default constructor.
+ io_port_ro()
+ : address(nullptr)
+ {
+ }
+
+ // Constructor.
+ io_port_ro(void* address_)
+ : address(reinterpret_cast<pointer_t>(address_))
+ {
+ }
+
+ void set_address(uintptr_t address_)
+ {
+ address = reinterpret_cast<pointer_t>(address_);
+ }
+
+ /// Get the IO port address.
+ pointer_t get_address()
+ {
+ return address;
+ }
+
+ /// Read.
+ operator T() volatile const
+ {
+ return *address;
+ }
+
+ /// Read.
+ T value() volatile const
+ {
+ return *address;
+ }
+
+ private:
+
+ typedef typename etl::parameter_type<T>::type parameter_t;
+
+ /// Write disabled.
+ void operator =(parameter_t value);
+
+ pointer_t address;
+ };
+
+ //***************************************************************************
+ /// Write only port.
+ /// Specialisation for dynamic addresses.
+ //***************************************************************************
+ template <typename T>
+ class io_port_wo<T, 0>
+ {
+ private:
+
+ typedef T* pointer_t;
+
+ public:
+
+ typedef typename etl::parameter_type<T>::type parameter_t;
+
+ // Default constructor.
+ io_port_wo()
+ : address(nullptr)
+ {
+ }
+
+ // Constructor.
+ io_port_wo(void* address_)
+ : address(reinterpret_cast<pointer_t>(address_))
+ {
+ }
+
+ /// Set the IO port address.
+ void set_address(uintptr_t address_)
+ {
+ address = reinterpret_cast<pointer_t>(address_);
+ }
+
+ /// Get the IO port address.
+ pointer_t get_address()
+ {
+ return address;
+ }
+
+ /// Write.
+ void operator =(parameter_t value)
+ {
+ *address = value;
+ }
+
+ private:
+
+ /// Read disabled.
+ operator T() volatile const;
+
+ pointer_t address;
+ };
+
+ //***************************************************************************
+ /// Write only port with shadow register.
+ /// Specialisation for dynamic addresses.
+ //***************************************************************************
+ template <typename T>
+ class io_port_wos<T, 0>
+ {
+ private:
+
+ typedef T* pointer_t;
+ typedef typename etl::parameter_type<T>::type parameter_t;
+
+ public:
+
+ // Default constructor.
+ io_port_wos()
+ : address(nullptr)
+ {
+ }
+
+ // Constructor.
+ io_port_wos(void* address_)
+ : address(reinterpret_cast<pointer_t>(address_))
+ {
+ }
+
+ /// Set the IO port address.
+ void set_address(uintptr_t address_)
+ {
+ address = reinterpret_cast<pointer_t>(address_);
+ }
+
+ /// Get the IO port address.
+ pointer_t get_address()
+ {
+ return address;
+ }
+
+ /// Read.
+ operator T() const
+ {
+ return shadow_value;
+ }
+
+ /// Read.
+ T value() const
+ {
+ return shadow_value;
+ }
+
+ /// Write.
+ io_port_wos& operator =(parameter_t value)
+ {
+ shadow_value = value;
+ *address = shadow_value;
+ return *this;
+ }
+
+ private:
+
+ T shadow_value;
+ pointer_t address;
+ };
+}
+
+#endif
diff --git a/lib/etl/ipool.h b/lib/etl/ipool.h
new file mode 100644
index 0000000..34c4e7d
--- /dev/null
+++ b/lib/etl/ipool.h
@@ -0,0 +1,522 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_IPOOL__
+#define __ETL_IPOOL__
+#define __ETL_IN_IPOOL_H__
+
+#include <iterator>
+
+#include "private/pool_base.h"
+#include "nullptr.h"
+#include "ibitset.h"
+#include "error_handler.h"
+
+namespace etl
+{
+ //***************************************************************************
+ ///\ingroup pool
+ //***************************************************************************
+ template <typename T>
+ class ipool : public pool_base
+ {
+ public:
+
+ typedef T value_type;
+ typedef T* pointer;
+ typedef const T* const_pointer;
+ typedef T& reference;
+ typedef const T& const_reference;
+ typedef size_t size_type;
+
+ //*************************************************************************
+ /// iterator
+ //*************************************************************************
+ class iterator : public std::iterator<std::forward_iterator_tag, const T>
+ {
+ public:
+
+ friend class ipool;
+ friend class const_iterator;
+
+ //*******************************
+ iterator()
+ : index(0),
+ p_buffer(nullptr),
+ p_in_use_flags(nullptr)
+ {
+ }
+
+ //*******************************
+ iterator(const iterator& other)
+ : index(other.index),
+ p_buffer(other.p_buffer),
+ p_in_use_flags(other.p_in_use_flags)
+ {
+ }
+
+ //*******************************
+ iterator& operator ++()
+ {
+ index = p_in_use_flags->find_next(true, index + 1);
+ return *this;
+ }
+
+ //*******************************
+ iterator operator ++(int)
+ {
+ iterator temp(*this);
+ index = p_in_use_flags->find_next(true, index + 1);
+ return temp;
+ }
+
+ //*******************************
+ iterator operator =(const iterator& other)
+ {
+ index = other.index;
+ p_buffer = other.p_buffer;
+ p_in_use_flags = other.p_in_use_flags;
+ return *this;
+ }
+
+ //*******************************
+ const_reference operator *() const
+ {
+ return p_buffer[index];
+ }
+
+ //*******************************
+ const_pointer operator ->() const
+ {
+ return &p_buffer[index];
+ }
+
+ //*******************************
+ friend bool operator == (const iterator& lhs, const iterator& rhs)
+ {
+ return (lhs.p_buffer == rhs.p_buffer) && (lhs.index == rhs.index);
+ }
+
+ //*******************************
+ friend bool operator != (const iterator& lhs, const iterator& rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+ private:
+
+ //*******************************
+ iterator(size_t index,
+ pointer p_buffer,
+ const ibitset* p_in_use_flags)
+ : index(index),
+ p_buffer(p_buffer),
+ p_in_use_flags(p_in_use_flags)
+ {
+ }
+
+ size_t index;
+ pointer p_buffer;
+ const ibitset* p_in_use_flags;
+ };
+
+
+ //*************************************************************************
+ /// const_iterator
+ //*************************************************************************
+ class const_iterator : public std::iterator<std::forward_iterator_tag, const T>
+ {
+ public:
+
+ friend class ipool;
+
+ //*******************************
+ const_iterator()
+ : index(0),
+ p_buffer(nullptr),
+ p_in_use_flags(nullptr)
+ {
+ }
+
+ //*******************************
+ const_iterator(const const_iterator& other)
+ : index(other.index),
+ p_buffer(other.p_buffer),
+ p_in_use_flags(other.p_in_use_flags)
+ {
+ }
+
+ //*******************************
+ const_iterator(const typename ipool::iterator& other)
+ : index(other.index),
+ p_buffer(other.p_buffer),
+ p_in_use_flags(other.p_in_use_flags)
+ {
+ }
+
+ //*******************************
+ const_iterator& operator ++()
+ {
+ index = p_in_use_flags->find_next(true, index + 1);
+ return *this;
+ }
+
+ //*******************************
+ const_iterator operator ++(int)
+ {
+ const_iterator temp(*this);
+ index = p_in_use_flags->find_next(true, index + 1);
+ return temp;
+ }
+
+ //*******************************
+ const_iterator operator =(const const_iterator& other)
+ {
+ index = other.index;
+ p_buffer = other.p_buffer;
+ p_in_use_flags = other.p_in_use_flags;
+ return *this;
+ }
+
+ //*******************************
+ const_reference operator *() const
+ {
+ return p_buffer[index];
+ }
+
+ //*******************************
+ const_pointer operator ->() const
+ {
+ return &p_buffer[index];
+ }
+
+ //*******************************
+ friend bool operator == (const const_iterator& lhs, const const_iterator& rhs)
+ {
+ return (lhs.p_buffer == rhs.p_buffer) && (lhs.index == rhs.index);
+ }
+
+ //*******************************
+ friend bool operator != (const const_iterator& lhs, const const_iterator& rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+ private:
+
+ //*******************************
+ const_iterator(size_t index,
+ const_pointer p_buffer,
+ const ibitset* p_in_use_flags)
+ : index(index),
+ p_buffer(p_buffer),
+ p_in_use_flags(p_in_use_flags)
+ {
+ }
+
+ size_t index;
+ const_pointer p_buffer;
+ const ibitset* p_in_use_flags;
+ };
+
+ //*************************************************************************
+ /// Get an iterator to the first allocated item in the pool.
+ //*************************************************************************
+ iterator begin()
+ {
+ size_t index = in_use_flags.find_first(true);
+
+ if (index != ibitset::npos)
+ {
+ return iterator(index, p_buffer, &in_use_flags);
+ }
+ else
+ {
+ return end();
+ }
+ }
+
+ //*************************************************************************
+ /// Get a const iterator to the first allocated item in the pool.
+ //*************************************************************************
+ const_iterator begin() const
+ {
+ size_t index = in_use_flags.find_first(true);
+
+ if (index != ibitset::npos)
+ {
+ return const_iterator(index, p_buffer, &in_use_flags);
+ }
+ else
+ {
+ return end();
+ }
+ }
+
+ //*************************************************************************
+ /// Get a const iterator to the first allocated item in the pool.
+ //*************************************************************************
+ const_iterator cbegin() const
+ {
+ return begin();
+ }
+
+ //*************************************************************************
+ /// Get an iterator to the end of the pool.
+ //*************************************************************************
+ iterator end()
+ {
+ return iterator(ibitset::npos, p_buffer, &in_use_flags);
+ }
+
+ //*************************************************************************
+ /// Get a const iterator to the end of the pool.
+ //*************************************************************************
+ const_iterator end() const
+ {
+ return const_iterator(ibitset::npos, p_buffer, &in_use_flags);
+ }
+
+ //*************************************************************************
+ /// Get a const iterator to the end of the pool.
+ //*************************************************************************
+ const_iterator cend() const
+ {
+ return end();
+ }
+
+ //*************************************************************************
+ /// Allocate an object from the pool.
+ /// Uses the default constructor.
+ /// If asserts or exceptions are enabled and there are no more free items an
+ /// etl::pool_no_allocation if thrown, otherwise a nullptr is returned.
+ /// \note The state of the object returned is undefined.
+ //*************************************************************************
+ T* allocate()
+ {
+#if defined(_DEBUG) || defined(DEBUG)
+ ETL_ASSERT(items_allocated < MAX_SIZE && !in_use_flags.test(next_free), ETL_ERROR(pool_no_allocation));
+#else
+ ETL_ASSERT(items_allocated < MAX_SIZE, ETL_ERROR(pool_no_allocation));
+#endif
+
+ T* result = new(&p_buffer[next_free]) T();
+
+ in_use_flags.set(next_free);
+ next_free = in_use_flags.find_first(false);
+ ++items_allocated;
+
+ return result;
+ }
+
+ //*************************************************************************
+ /// Allocate an object from the pool from an initial value.
+ /// If asserts or exceptions are enabled and there are no more free items an
+ /// etl::pool_no_allocation if thrown, otherwise a nullptr is returned.
+ /// \note The state of the object returned is undefined.
+ //*************************************************************************
+ T* allocate(const T& initial)
+ {
+#if defined(_DEBUG) || defined(DEBUG)
+ ETL_ASSERT(items_allocated < MAX_SIZE && !in_use_flags.test(next_free), ETL_ERROR(pool_no_allocation));
+#else
+ ETL_ASSERT(items_allocated < MAX_SIZE, ETL_ERROR(pool_no_allocation));
+#endif
+
+ T* result = new(&p_buffer[next_free]) T(initial);
+
+ in_use_flags.set(next_free);
+ next_free = in_use_flags.find_first(false);
+ ++items_allocated;
+
+ return result;
+ }
+
+ //*************************************************************************
+ /// Release an object in the pool.
+ /// If asserts or exceptions are enabled and the object does not belong to this
+ /// pool then an etl::pool_object_not_in_pool is thrown.
+ /// \param p_object A pointer to the object to be released.
+ //*************************************************************************
+ void release(const T& object)
+ {
+ release(&object);
+ }
+
+ //*************************************************************************
+ /// Release an object in the pool.
+ /// If asserts or exceptions are enabled and the object does not belong to this
+ /// pool then an etl::pool_object_not_in_pool is thrown.
+ /// \param p_object A pointer to the object to be released.
+ //*************************************************************************
+ void release(const T* const p_object)
+ {
+ // Does it belong to me?
+ ETL_ASSERT(is_in_pool(p_object), ETL_ERROR(pool_object_not_in_pool));
+
+ // Where is it in the buffer?
+ typename std::iterator_traits<T*>::difference_type distance = p_object - p_buffer;
+ size_t index = static_cast<size_t>(distance);
+
+ // Check that it hasn't already been released.
+ if (in_use_flags.test(index))
+ {
+ // Destroy the object and mark as available.
+ p_object->~T();
+ in_use_flags.reset(index);
+ --items_allocated;
+ next_free = index;
+ }
+ }
+
+ //*************************************************************************
+ /// Releases all objects in the pool.
+ //*************************************************************************
+ void release_all()
+ {
+ const_iterator i_object = begin();
+
+ while (i_object != end())
+ {
+ i_object->~T();
+ ++i_object;
+ }
+
+ in_use_flags.reset();
+ items_allocated = 0;
+ next_free = 0;
+ }
+
+ //*************************************************************************
+ /// Check to see if the object belongs to the pool.
+ /// \param p_object A pointer to the object to be checked.
+ /// \return <b>true<\b> if it does, otherwise <b>false</b>
+ //*************************************************************************
+ bool is_in_pool(const T& object) const
+ {
+ return is_in_pool(&object);
+ }
+
+ //*************************************************************************
+ /// Check to see if the object belongs to the pool.
+ /// \param p_object A pointer to the object to be checked.
+ /// \return <b>true<\b> if it does, otherwise <b>false</b>
+ //*************************************************************************
+ bool is_in_pool(const T* p_object) const
+ {
+ // Does this object belong to this pool?
+ typename std::iterator_traits<T*>::difference_type distance = p_object - p_buffer;
+
+ // Within the range of the buffer?
+ return ((distance >= 0) && (distance < static_cast<typename std::iterator_traits<T*>::difference_type>(MAX_SIZE)));
+ }
+
+ //*************************************************************************
+ /// Gets the iterator to the object.
+ /// If the object is not in the pool then end() is returned.
+ /// \param object A const reference to the object to be checked.
+ /// \return An iterator to the object or end().
+ //*************************************************************************
+ iterator get_iterator(T& object)
+ {
+ if (is_in_pool(object))
+ {
+ iterator i_object = begin();
+
+ while (i_object != end())
+ {
+ // Same one?
+ if (&object == &*i_object)
+ {
+ return i_object;
+ }
+
+ ++i_object;
+ }
+ }
+
+ return end();
+ }
+
+ //*************************************************************************
+ /// Gets the const_iterator to the object.
+ /// If the object is not in the pool then end() is returned.
+ /// \param object A const reference to the object to be checked.
+ /// \return An const_iterator to the object or end().
+ //*************************************************************************
+ const_iterator get_iterator(const T& object) const
+ {
+ if (is_in_pool(object))
+ {
+ const_iterator i_object = begin();
+
+ while (i_object != end())
+ {
+ // Same one?
+ if (&object == &*i_object)
+ {
+ return i_object;
+ }
+
+ ++i_object;
+ }
+ }
+
+ return end();
+ }
+
+
+ protected:
+
+ //*************************************************************************
+ /// Constructor
+ //*************************************************************************
+ ipool(T* p_buffer, ibitset& in_use_flags, size_t size)
+ : pool_base(size),
+ p_buffer(p_buffer),
+ in_use_flags(in_use_flags)
+ {
+ }
+
+ private:
+
+ // Disable copy construction and assignment.
+ ipool(const ipool&);
+ ipool& operator =(const ipool&);
+
+ T* p_buffer;
+ ibitset& in_use_flags;
+ };
+}
+
+#undef __ETL_IN_IPOOL_H__
+
+#endif
+
diff --git a/lib/etl/ipriority_queue.h b/lib/etl/ipriority_queue.h
new file mode 100644
index 0000000..fd3cb83
--- /dev/null
+++ b/lib/etl/ipriority_queue.h
@@ -0,0 +1,275 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2015 jwellbelove, rlindeman
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_IPRIORITY_QUEUE__
+#define __ETL_IPRIORITY_QUEUE__
+
+#include <stddef.h>
+#include <algorithm>
+
+#include "type_traits.h"
+#include "parameter_type.h"
+#include "error_handler.h"
+#include "exception.h"
+
+#undef ETL_FILE
+#define ETL_FILE "12"
+
+namespace etl
+{
+ //***************************************************************************
+ /// The base class for priority_queue exceptions.
+ ///\ingroup queue
+ //***************************************************************************
+ class priority_queue_exception : public exception
+ {
+ public:
+
+ priority_queue_exception(string_type what, string_type file_name, numeric_type line_number)
+ : exception(what, file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// The exception thrown when the queue is full.
+ ///\ingroup queue
+ //***************************************************************************
+ class priority_queue_full : public priority_queue_exception
+ {
+ public:
+
+ priority_queue_full(string_type file_name, numeric_type line_number)
+ : priority_queue_exception(ETL_ERROR_TEXT("priority_queue:full", ETL_FILE"A"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// The priority queue iterator exception on reversed iterators
+ ///\ingroup queue
+ //***************************************************************************
+ class priority_queue_iterator : public priority_queue_exception
+ {
+ public:
+
+ priority_queue_iterator(string_type file_name, numeric_type line_number)
+ : priority_queue_exception(ETL_ERROR_TEXT("priority_queue:iterator", ETL_FILE"B"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ ///\ingroup queue
+ ///\brief This is the base for all priority queues that contain a particular type.
+ ///\details Normally a reference to this type will be taken from a derived queue.
+ /// The TContainer specified must provide the front, push_back, pop_back, and
+ /// assign methods to work correctly with priority_queue.
+ ///\code
+ /// etl::priority_queue<int, 10> myPriorityQueue;
+ /// etl::ipriority_queue<int>& iQueue = myPriorityQueue;
+ ///\endcode
+ /// \warning This priority queue cannot be used for concurrent access from
+ /// multiple threads.
+ /// \tparam T The type of value that the queue holds.
+ /// \tparam TContainer to hold the T queue values
+ /// \tparam TCompare to use in comparing T values
+ //***************************************************************************
+ template <typename T, typename TContainer, typename TCompare>
+ class ipriority_queue
+ {
+ public:
+
+ typedef T value_type; ///< The type stored in the queue.
+ typedef TContainer container_type; ///< The container type used for priority queue.
+ typedef TCompare compare_type; ///< The comparison type.
+ typedef T& reference; ///< A reference to the type used in the queue.
+ typedef const T& const_reference; ///< A const reference to the type used in the queue.
+ typedef typename TContainer::size_type size_type; ///< The type used for determining the size of the queue.
+ typedef typename std::iterator_traits<typename TContainer::iterator>::difference_type difference_type;
+
+ private:
+
+ typedef typename parameter_type<T>::type parameter_t;
+
+ public:
+
+ //*************************************************************************
+ /// Gets a reference to the highest priority value in the priority queue.<br>
+ /// \return A reference to the highest priority value in the priority queue.
+ //*************************************************************************
+ reference top()
+ {
+ return container.front();
+ }
+
+ //*************************************************************************
+ /// Gets a const reference to the highest priority value in the priority queue.<br>
+ /// \return A const reference to the highest priority value in the priority queue.
+ //*************************************************************************
+ const_reference top() const
+ {
+ return container.front();
+ }
+
+ //*************************************************************************
+ /// Adds a value to the queue.
+ /// If asserts or exceptions are enabled, throws an etl::priority_queue_full
+ /// is the priority queue is already full, otherwise does nothing if full.
+ ///\param value The value to push to the queue.
+ //*************************************************************************
+ void push(parameter_t value)
+ {
+ ETL_ASSERT(!full(), ETL_ERROR(priority_queue_full));
+
+ // Put element at end
+ container.push_back(value);
+ // Make elements in container into heap
+ std::push_heap(container.begin(), container.end(), TCompare());
+ }
+
+ //*************************************************************************
+ /// Assigns values to the priority queue.
+ /// If asserts or exceptions are enabled, emits priority_queue_full if
+ /// priority queue does not have enough free space.
+ /// If asserts or exceptions are enabled, emits priority_iterator if the
+ /// iterators are reversed.
+ ///\param first The iterator to the first element.
+ ///\param last The iterator to the last element + 1.
+ //*************************************************************************
+ template <typename TIterator>
+ void assign(TIterator first, TIterator last)
+ {
+#ifdef _DEBUG
+ difference_type count = std::distance(first, last);
+ ETL_ASSERT(count >= 0, ETL_ERROR(priority_queue_iterator));
+ ETL_ASSERT(static_cast<size_t>(count) <= max_size(), ETL_ERROR(priority_queue_full));
+#endif
+
+ clear();
+ container.assign(first, last);
+ std::make_heap(container.begin(), container.end(), TCompare());
+ }
+
+ //*************************************************************************
+ /// Removes the oldest value from the back of the priority queue.
+ /// Does nothing if the priority queue is already empty.
+ //*************************************************************************
+ void pop()
+ {
+ if (!empty())
+ {
+ // Move largest element to end
+ std::pop_heap(container.begin(), container.end(), TCompare());
+ // Actually remove largest element at end
+ container.pop_back();
+ }
+ }
+
+ //*************************************************************************
+ /// Returns the current number of items in the priority queue.
+ //*************************************************************************
+ size_type size() const
+ {
+ return container.size();
+ }
+
+ //*************************************************************************
+ /// Returns the maximum number of items that can be queued.
+ //*************************************************************************
+ size_type max_size() const
+ {
+ return container.max_size();
+ }
+
+ //*************************************************************************
+ /// Checks to see if the priority queue is empty.
+ /// \return <b>true</b> if the queue is empty, otherwise <b>false</b>
+ //*************************************************************************
+ bool empty() const
+ {
+ return container.empty();
+ }
+
+ //*************************************************************************
+ /// Checks to see if the priority queue is full.
+ /// \return <b>true</b> if the priority queue is full, otherwise <b>false</b>
+ //*************************************************************************
+ bool full() const
+ {
+ return container.size() == container.max_size();
+ }
+
+ //*************************************************************************
+ /// Returns the remaining capacity.
+ ///\return The remaining capacity.
+ //*************************************************************************
+ size_t available() const
+ {
+ return container.max_size() - container.size();
+ }
+
+ //*************************************************************************
+ /// Clears the queue to the empty state.
+ //*************************************************************************
+ void clear()
+ {
+ container.clear();
+ }
+
+ protected:
+
+ //*************************************************************************
+ /// Make this a clone of the supplied priority queue
+ //*************************************************************************
+ void clone(const ipriority_queue& other)
+ {
+ assign(other.container.cbegin(), other.container.cend());
+ }
+
+ //*************************************************************************
+ /// The constructor that is called from derived classes.
+ //*************************************************************************
+ ipriority_queue()
+ {
+ }
+
+ private:
+
+ // Disable copy construction.
+ ipriority_queue(const ipriority_queue&);
+
+ /// The container specified at instantiation of the priority_queue
+ TContainer container;
+ };
+}
+
+#undef ETL_FILE
+#endif
diff --git a/lib/etl/iqueue.h b/lib/etl/iqueue.h
new file mode 100644
index 0000000..0f55963
--- /dev/null
+++ b/lib/etl/iqueue.h
@@ -0,0 +1,225 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_IQUEUE__
+#define __ETL_IQUEUE__
+#define __ETL_IN_IQUEUE_H__
+
+#include <stddef.h>
+
+#include "private/queue_base.h"
+#include "type_traits.h"
+#include "parameter_type.h"
+#include "error_handler.h"
+
+namespace etl
+{
+ //***************************************************************************
+ ///\ingroup queue
+ ///\brief This is the base for all queues that contain a particular type.
+ ///\details Normally a reference to this type will be taken from a derived queue.
+ ///\code
+ /// etl::queue<int, 10> myQueue;
+ /// etl::iqueue<int>& iQueue = myQueue;
+ ///\endcode
+ /// \warning This queue cannot be used for concurrent access from multiple threads.
+ /// \tparam T The type of value that the queue holds.
+ //***************************************************************************
+ template <typename T>
+ class iqueue : public queue_base
+ {
+ public:
+
+ typedef T value_type; ///< The type stored in the queue.
+ typedef T& reference; ///< A reference to the type used in the queue.
+ typedef const T& const_reference; ///< A const reference to the type used in the queue.
+ typedef T* pointer; ///< A pointer to the type used in the queue.
+ typedef const T* const_pointer; ///< A const pointer to the type used in the queue.
+ typedef queue_base::size_type size_type; ///< The type used for determining the size of the queue.
+
+ private:
+
+ typedef typename parameter_type<T>::type parameter_t;
+
+ public:
+
+ //*************************************************************************
+ /// Gets a reference to the value at the front of the queue.<br>
+ /// \return A reference to the value at the front of the queue.
+ //*************************************************************************
+ reference front()
+ {
+ return p_buffer[out];
+ }
+
+ //*************************************************************************
+ /// Gets a const reference to the value at the front of the queue.<br>
+ /// \return A const reference to the value at the front of the queue.
+ //*************************************************************************
+ const_reference front() const
+ {
+ return p_buffer[out];
+ }
+
+ //*************************************************************************
+ /// Gets a reference to the value at the back of the queue.<br>
+ /// \return A reference to the value at the back of the queue.
+ //*************************************************************************
+ reference back()
+ {
+ return p_buffer[in == 0 ? MAX_SIZE - 1 : in - 1];
+ }
+
+ //*************************************************************************
+ /// Gets a const reference to the value at the back of the queue.<br>
+ /// \return A const reference to the value at the back of the queue.
+ //*************************************************************************
+ const_reference back() const
+ {
+ return p_buffer[in == 0 ? MAX_SIZE - 1 : in - 1];
+ }
+
+ //*************************************************************************
+ /// Adds a value to the queue.
+ /// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full,
+ /// otherwise does nothing if full.
+ ///\param value The value to push to the queue.
+ //*************************************************************************
+ void push(parameter_t value)
+ {
+#if defined(ETL_CHECK_PUSH_POP)
+ ETL_ASSERT(!full(), ETL_ERROR(queue_full));
+#endif
+ new(&p_buffer[in]) T(value);
+ in = (in == (MAX_SIZE - 1)) ? 0 : in + 1;
+ ++current_size;
+ }
+
+ //*************************************************************************
+ /// Allows a possibly more efficient 'push' by moving to the next input value
+ /// and returning a reference to it.
+ /// This may eliminate a copy by allowing direct construction in-place.<br>
+ /// If asserts or exceptions are enabled, throws an etl::queue_full is the queue is already full,
+ /// otherwise does nothing if full.
+ /// \return A reference to the position to 'push' to.
+ //*************************************************************************
+ reference push()
+ {
+ const size_type next = in;
+
+#if defined(ETL_CHECK_PUSH_POP)
+ ETL_ASSERT(!full(), ETL_ERROR(queue_full));
+#endif
+ new(&p_buffer[in]) T();
+ in = (in == (MAX_SIZE - 1)) ? 0 : in + 1;
+ ++current_size;
+
+ return p_buffer[next];
+ }
+
+ //*************************************************************************
+ /// Clears the queue to the empty state.
+ //*************************************************************************
+ void clear()
+ {
+ while (current_size > 0)
+ {
+ p_buffer[out].~T();
+ out = (out == (MAX_SIZE - 1)) ? 0 : out + 1;
+ --current_size;
+ }
+
+ in = 0;
+ out = 0;
+ }
+
+ //*************************************************************************
+ /// Removes the oldest value from the back of the queue.
+ /// Does nothing if the queue is already empty.
+ //*************************************************************************
+ void pop()
+ {
+#if defined(ETL_CHECK_PUSH_POP)
+ ETL_ASSERT(!empty(), ETL_ERROR(queue_empty));
+#endif
+ p_buffer[out].~T();
+ out = (out == (MAX_SIZE - 1)) ? 0 : out + 1;
+ --current_size;
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ iqueue& operator = (const iqueue& rhs)
+ {
+ if (&rhs != this)
+ {
+ clone(rhs);
+ }
+
+ return *this;
+ }
+
+ protected:
+
+ //*************************************************************************
+ /// Make this a clone of the supplied queue
+ //*************************************************************************
+ void clone(const iqueue& other)
+ {
+ size_t index = other.out;
+
+ for (size_t i = 0; i < other.size(); ++i)
+ {
+ push(other.p_buffer[index]);
+ index = (index == (MAX_SIZE - 1)) ? 0 : index + 1;
+ }
+ }
+
+ //*************************************************************************
+ /// The constructor that is called from derived classes.
+ //*************************************************************************
+ iqueue(T* p_buffer, size_type max_size)
+ : queue_base(max_size),
+ p_buffer(p_buffer)
+ {
+ }
+
+ private:
+
+ // Disable copy construction.
+ iqueue(const iqueue&);
+
+ T* p_buffer; ///< The internal buffer.
+ };
+}
+
+#undef __ETL_IN_IQUEUE_H__
+#endif
diff --git a/lib/etl/iset.h b/lib/etl/iset.h
new file mode 100644
index 0000000..83f495c
--- /dev/null
+++ b/lib/etl/iset.h
@@ -0,0 +1,1622 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove, rlindeman
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_ISET__
+#define __ETL_ISET__
+#define __ETL_IN_ISET_H__
+
+#include <iterator>
+#include <algorithm>
+#include <functional>
+#include <stddef.h>
+
+#include "nullptr.h"
+#include "private/set_base.h"
+#include "type_traits.h"
+#include "parameter_type.h"
+#include "pool.h"
+#include "platform.h"
+
+#ifdef ETL_COMPILER_MICROSOFT
+#undef min
+#endif
+
+namespace etl
+{
+ //***************************************************************************
+ /// A templated base for all etl::set types.
+ ///\ingroup set
+ //***************************************************************************
+ template <typename T, typename TCompare>
+ class iset : public set_base
+ {
+ public:
+
+ typedef const T key_type;
+ typedef const T value_type;
+ typedef TCompare key_compare;
+ typedef TCompare value_compare;
+ typedef value_type& const_reference;
+ typedef value_type* const_pointer;
+ typedef size_t size_type;
+
+ //*************************************************************************
+ /// How to compare two key elements.
+ //*************************************************************************
+ struct key_comp
+ {
+ bool operator ()(key_type& key1, key_type& key2) const
+ {
+ return key_compare()(key1, key2);
+ }
+ };
+
+ //*************************************************************************
+ /// How to compare two value elements.
+ //*************************************************************************
+ struct value_comp
+ {
+ bool operator ()(value_type& value1, value_type& value2) const
+ {
+ return value_compare()(value1, value2);
+ }
+ };
+
+ protected:
+
+ //*************************************************************************
+ /// The data node element in the set.
+ //*************************************************************************
+ struct Data_Node : public Node
+ {
+ explicit Data_Node(value_type value)
+ : value(value)
+ {
+ }
+
+ value_type value;
+ };
+
+ /// Defines the key value parameter type
+ typedef typename parameter_type<T>::type key_value_parameter_t;
+
+ //*************************************************************************
+ /// How to compare node elements.
+ //*************************************************************************
+ bool node_comp(const Data_Node& node1, const Data_Node& node2) const
+ {
+ return key_compare()(node1.value, node2.value);
+ }
+ bool node_comp(const Data_Node& node, const key_value_parameter_t& key) const
+ {
+ return key_compare()(node.value, key);
+ }
+ bool node_comp(const key_value_parameter_t& key, const Data_Node& node) const
+ {
+ return key_compare()(key, node.value);
+ }
+
+ private:
+
+ /// The pool of data nodes used in the set.
+ ipool<Data_Node>* p_node_pool;
+
+ //*************************************************************************
+ /// Downcast a Node* to a Data_Node*
+ //*************************************************************************
+ static Data_Node* data_cast(Node* p_node)
+ {
+ return static_cast<Data_Node*>(p_node);
+ }
+
+ //*************************************************************************
+ /// Downcast a Node& to a Data_Node&
+ //*************************************************************************
+ static Data_Node& data_cast(Node& node)
+ {
+ return static_cast<Data_Node&>(node);
+ }
+
+ //*************************************************************************
+ /// Downcast a const Node* to a const Data_Node*
+ //*************************************************************************
+ static const Data_Node* data_cast(const Node* p_node)
+ {
+ return static_cast<const Data_Node*>(p_node);
+ }
+
+ //*************************************************************************
+ /// Downcast a const Node& to a const Data_Node&
+ //*************************************************************************
+ static const Data_Node& data_cast(const Node& node)
+ {
+ return static_cast<const Data_Node&>(node);
+ }
+
+ public:
+ //*************************************************************************
+ /// iterator.
+ //*************************************************************************
+ class iterator : public std::iterator<std::bidirectional_iterator_tag, value_type>
+ {
+ public:
+
+ friend class iset;
+
+ iterator()
+ : p_set(nullptr)
+ , p_node(nullptr)
+ {
+ }
+
+ iterator(iset& set)
+ : p_set(&set)
+ , p_node(nullptr)
+ {
+ }
+
+ iterator(iset& set, Node* node)
+ : p_set(&set)
+ , p_node(node)
+ {
+ }
+
+ iterator(const iterator& other)
+ : p_set(other.p_set)
+ , p_node(other.p_node)
+ {
+ }
+
+ ~iterator()
+ {
+ }
+
+ iterator& operator ++()
+ {
+ p_set->next_node(p_node);
+ return *this;
+ }
+
+ iterator operator ++(int)
+ {
+ iterator temp(*this);
+ p_set->next_node(p_node);
+ return temp;
+ }
+
+ iterator& operator --()
+ {
+ p_set->prev_node(p_node);
+ return *this;
+ }
+
+ iterator operator --(int)
+ {
+ iterator temp(*this);
+ p_set->prev_node(p_node);
+ return temp;
+ }
+
+ iterator operator =(const iterator& other)
+ {
+ p_set = other.p_set;
+ p_node = other.p_node;
+ return *this;
+ }
+
+ const_reference operator *() const
+ {
+ return iset::data_cast(p_node)->value;
+ }
+
+ const_pointer operator &() const
+ {
+ return &(iset::data_cast(p_node)->value);
+ }
+
+ const_pointer operator ->() const
+ {
+ return &(iset::data_cast(p_node)->value);
+ }
+
+ friend bool operator == (const iterator& lhs, const iterator& rhs)
+ {
+ return lhs.p_set == rhs.p_set && lhs.p_node == rhs.p_node;
+ }
+
+ friend bool operator != (const iterator& lhs, const iterator& rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+ private:
+
+ // Pointer to set associated with this iterator
+ iset* p_set;
+
+ // Pointer to the current node for this iterator
+ Node* p_node;
+ };
+ friend class iterator;
+
+ //*************************************************************************
+ /// const_iterator
+ //*************************************************************************
+ class const_iterator : public std::iterator<std::bidirectional_iterator_tag, const value_type>
+ {
+ public:
+
+ friend class iset;
+
+ const_iterator()
+ : p_set(nullptr)
+ , p_node(nullptr)
+ {
+ }
+
+ const_iterator(const iset& set)
+ : p_set(&set)
+ , p_node(nullptr)
+ {
+ }
+
+ const_iterator(const iset& set, const Node* node)
+ : p_set(&set)
+ , p_node(node)
+ {
+ }
+
+ const_iterator(const typename iset::iterator& other)
+ : p_set(other.p_set)
+ , p_node(other.p_node)
+ {
+ }
+
+ const_iterator(const const_iterator& other)
+ : p_set(other.p_set)
+ , p_node(other.p_node)
+ {
+ }
+
+ ~const_iterator()
+ {
+ }
+
+ const_iterator& operator ++()
+ {
+ p_set->next_node(p_node);
+ return *this;
+ }
+
+ const_iterator operator ++(int)
+ {
+ const_iterator temp(*this);
+ p_set->next_node(p_node);
+ return temp;
+ }
+
+ const_iterator& operator --()
+ {
+ p_set->prev_node(p_node);
+ return *this;
+ }
+
+ const_iterator operator --(int)
+ {
+ const_iterator temp(*this);
+ p_set->prev_node(p_node);
+ return temp;
+ }
+
+ const_iterator operator =(const const_iterator& other)
+ {
+ p_set = other.p_set;
+ p_node = other.p_node;
+ return *this;
+ }
+
+ const_reference operator *() const
+ {
+ return iset::data_cast(p_node)->value;
+ }
+
+ const_pointer operator &() const
+ {
+ return iset::data_cast(p_node)->value;
+ }
+
+ const_pointer operator ->() const
+ {
+ return &(iset::data_cast(p_node)->value);
+ }
+
+ friend bool operator == (const const_iterator& lhs, const const_iterator& rhs)
+ {
+ return lhs.p_set == rhs.p_set && lhs.p_node == rhs.p_node;
+ }
+
+ friend bool operator != (const const_iterator& lhs, const const_iterator& rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+ private:
+ // Pointer to set associated with this iterator
+ const iset* p_set;
+
+ // Pointer to the current node for this iterator
+ const Node* p_node;
+ };
+ friend class const_iterator;
+
+ typedef typename std::iterator_traits<iterator>::difference_type difference_type;
+
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ iset& operator = (const iset& rhs)
+ {
+ if (this != &rhs)
+ {
+ assign(rhs.cbegin(), rhs.cend());
+ }
+
+ return *this;
+ }
+
+ //*************************************************************************
+ /// Gets the beginning of the set.
+ //*************************************************************************
+ iterator begin()
+ {
+ return iterator(*this, find_limit_node(root_node, kLeft));
+ }
+
+ //*************************************************************************
+ /// Gets the beginning of the set.
+ //*************************************************************************
+ const_iterator begin() const
+ {
+ return const_iterator(*this, find_limit_node(root_node, kLeft));
+ }
+
+ //*************************************************************************
+ /// Gets the end of the set.
+ //*************************************************************************
+ iterator end()
+ {
+ return iterator(*this);
+ }
+
+ //*************************************************************************
+ /// Gets the end of the set.
+ //*************************************************************************
+ const_iterator end() const
+ {
+ return const_iterator(*this);
+ }
+
+ //*************************************************************************
+ /// Gets the beginning of the set.
+ //*************************************************************************
+ const_iterator cbegin() const
+ {
+ return const_iterator(*this, find_limit_node(root_node, kLeft));
+ }
+
+ //*************************************************************************
+ /// Gets the end of the set.
+ //*************************************************************************
+ const_iterator cend() const
+ {
+ return const_iterator(*this);
+ }
+
+ //*************************************************************************
+ /// Gets the reverse beginning of the list.
+ //*************************************************************************
+ reverse_iterator rbegin()
+ {
+ return reverse_iterator(iterator(*this));
+ }
+
+ //*************************************************************************
+ /// Gets the reverse beginning of the list.
+ //*************************************************************************
+ const_reverse_iterator rbegin() const
+ {
+ return const_reverse_iterator(const_iterator(*this));
+ }
+
+ //*************************************************************************
+ /// Gets the reverse end of the list.
+ //*************************************************************************
+ reverse_iterator rend()
+ {
+ return reverse_iterator(iterator(*this, find_limit_node(root_node, kLeft)));
+ }
+
+ //*************************************************************************
+ /// Gets the reverse end of the list.
+ //*************************************************************************
+ const_reverse_iterator rend() const
+ {
+ return const_reverse_iterator(iterator(*this, find_limit_node(root_node, kLeft)));
+ }
+
+ //*************************************************************************
+ /// Gets the reverse beginning of the list.
+ //*************************************************************************
+ const_reverse_iterator crbegin() const
+ {
+ return const_reverse_iterator(const_iterator(*this));
+ }
+
+ //*************************************************************************
+ /// Gets the reverse end of the list.
+ //*************************************************************************
+ const_reverse_iterator crend() const
+ {
+ return const_reverse_iterator(const_iterator(*this, find_limit_node(root_node, kLeft)));
+ }
+
+ //*********************************************************************
+ /// Assigns values to the set.
+ /// If asserts or exceptions are enabled, emits set_full if the set does not have enough free space.
+ /// If asserts or exceptions are enabled, emits set_iterator if the iterators are reversed.
+ ///\param first The iterator to the first element.
+ ///\param last The iterator to the last element + 1.
+ //*********************************************************************
+ template <typename TIterator>
+ void assign(TIterator first, TIterator last)
+ {
+ initialise();
+ insert(first, last);
+ }
+
+ //*************************************************************************
+ /// Clears the set.
+ //*************************************************************************
+ void clear()
+ {
+ initialise();
+ }
+
+ //*********************************************************************
+ /// Counts the number of elements that contain the key specified.
+ ///\param key The key to search for.
+ ///\return 1 if element was found, 0 otherwise.
+ //*********************************************************************
+ size_type count(const key_value_parameter_t& key) const
+ {
+ return find_node(root_node, key) ? 1 : 0;
+ }
+
+ //*************************************************************************
+ /// Returns two iterators with bounding (lower bound, upper bound) the
+ /// value provided
+ //*************************************************************************
+ std::pair<iterator, iterator> equal_range(const value_type& value)
+ {
+ return std::make_pair<iterator, iterator>(
+ iterator(*this, find_lower_node(root_node, value)),
+ iterator(*this, find_upper_node(root_node, value)));
+ }
+
+ //*************************************************************************
+ /// Returns two const iterators with bounding (lower bound, upper bound)
+ /// the value provided.
+ //*************************************************************************
+ std::pair<const_iterator, const_iterator> equal_range(const value_type& value) const
+ {
+ return std::make_pair<const_iterator, const_iterator>(
+ const_iterator(*this, find_lower_node(root_node, value)),
+ const_iterator(*this, find_upper_node(root_node, value)));
+ }
+
+ //*************************************************************************
+ /// Erases the value at the specified position.
+ //*************************************************************************
+ void erase(iterator position)
+ {
+ // Remove the node by its key
+ erase((*position));
+ }
+
+ //*************************************************************************
+ /// Erases the value at the specified position.
+ //*************************************************************************
+ iterator erase(const_iterator position)
+ {
+ // Find the parent node to be removed
+ Node*& reference_node = find_node(root_node, position.p_node);
+ iterator next(*this, reference_node);
+ ++next;
+
+ remove_node(root_node, (*position));
+
+ return next;
+ }
+
+ //*************************************************************************
+ // Erase the key specified.
+ //*************************************************************************
+ size_type erase(const key_value_parameter_t& key_value)
+ {
+ // Return 1 if key value was found and removed
+ return remove_node(root_node, key_value) ? 1 : 0;
+ }
+
+ //*************************************************************************
+ /// Erases a range of elements.
+ //*************************************************************************
+ iterator erase(iterator first, iterator last)
+ {
+ iterator next;
+ while (first != last)
+ {
+ next = erase(const_iterator(first++));
+ }
+
+ return next;
+ }
+
+ //*************************************************************************
+ /// Erases a range of elements.
+ //*************************************************************************
+ iterator erase(const_iterator first, const_iterator last)
+ {
+ iterator next;
+ while (first != last)
+ {
+ next = erase(first++);
+ }
+
+ return next;
+ }
+
+ //*********************************************************************
+ /// Finds an element.
+ ///\param key The key to search for.
+ ///\return An iterator pointing to the element or end() if not found.
+ //*********************************************************************
+ iterator find(const key_value_parameter_t& key_value)
+ {
+ return iterator(*this, find_node(root_node, key_value));
+ }
+
+ //*********************************************************************
+ /// Finds an element.
+ ///\param key The key to search for.
+ ///\return An iterator pointing to the element or end() if not found.
+ //*********************************************************************
+ const_iterator find(const key_value_parameter_t& key_value) const
+ {
+ return const_iterator(*this, find_node(root_node, key_value));
+ }
+
+ //*********************************************************************
+ /// Inserts a value to the set.
+ /// If asserts or exceptions are enabled, emits set_full if the set is already full.
+ ///\param value The value to insert.
+ //*********************************************************************
+ std::pair<iterator, bool> insert(value_type& value)
+ {
+ // Default to no inserted node
+ Node* inserted_node = nullptr;
+ bool inserted = false;
+
+ ETL_ASSERT(!full(), ETL_ERROR(set_full));
+
+ // Get next available free node
+ Data_Node& node = allocate_data_node(value);
+
+ // Obtain the inserted node (might be nullptr if node was a duplicate)
+ inserted_node = insert_node(root_node, node);
+ inserted = inserted_node == &node;
+
+ // Insert node into tree and return iterator to new node location in tree
+ return std::make_pair(iterator(*this, inserted_node), inserted);
+ }
+
+ //*********************************************************************
+ /// Inserts a value to the set starting at the position recommended.
+ /// If asserts or exceptions are enabled, emits set_full if the set is already full.
+ ///\param position The position that would precede the value to insert.
+ ///\param value The value to insert.
+ //*********************************************************************
+ iterator insert(iterator, value_type& value)
+ {
+ // Default to no inserted node
+ Node* inserted_node = nullptr;
+
+ ETL_ASSERT(!full(), ETL_ERROR(set_full));
+
+ // Get next available free node
+ Data_Node& node = allocate_data_node(value);
+
+ // Obtain the inserted node (might be nullptr if node was a duplicate)
+ inserted_node = insert_node(root_node, node);
+
+ // Insert node into tree and return iterator to new node location in tree
+ return iterator(*this, inserted_node);
+ }
+
+ //*********************************************************************
+ /// Inserts a value to the set starting at the position recommended.
+ /// If asserts or exceptions are enabled, emits set_full if the set is already full.
+ ///\param position The position that would precede the value to insert.
+ ///\param value The value to insert.
+ //*********************************************************************
+ iterator insert(const_iterator, value_type& value)
+ {
+ // Default to no inserted node
+ Node* inserted_node = nullptr;
+
+ ETL_ASSERT(!full(), ETL_ERROR(set_full));
+
+ // Get next available free node
+ Data_Node& node = allocate_data_node(value);
+
+ // Obtain the inserted node (might be nullptr if node was a duplicate)
+ inserted_node = insert_node(root_node, node);
+
+ // Insert node into tree and return iterator to new node location in tree
+ return iterator(*this, inserted_node);
+ }
+
+ //*********************************************************************
+ /// Inserts a range of values to the set.
+ /// If asserts or exceptions are enabled, emits set_full if the set does not have enough free space.
+ ///\param position The position to insert at.
+ ///\param first The first element to add.
+ ///\param last The last + 1 element to add.
+ //*********************************************************************
+ template <class TIterator>
+ void insert(TIterator first, TIterator last)
+ {
+ while (first != last)
+ {
+ insert(*first++);
+ }
+ }
+
+ //*********************************************************************
+ /// Returns an iterator pointing to the first element in the container
+ /// whose key is not considered to go before the key provided or end()
+ /// if all keys are considered to go before the key provided.
+ ///\return An iterator pointing to the element not before key or end()
+ //*********************************************************************
+ iterator lower_bound(const key_value_parameter_t& key)
+ {
+ return iterator(*this, find_lower_node(root_node, key));
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator pointing to the first element in the
+ /// container whose key is not considered to go before the key provided
+ /// or end() if all keys are considered to go before the key provided.
+ ///\return An const_iterator pointing to the element not before key or end()
+ //*********************************************************************
+ const_iterator lower_bound(const key_value_parameter_t& key) const
+ {
+ return const_iterator(*this, find_lower_node(root_node, key));
+ }
+
+ //*********************************************************************
+ /// Returns an iterator pointing to the first element in the container
+ /// whose key is not considered to go after the key provided or end()
+ /// if all keys are considered to go after the key provided.
+ ///\return An iterator pointing to the element after key or end()
+ //*********************************************************************
+ iterator upper_bound(const key_value_parameter_t& key)
+ {
+ return iterator(*this, find_upper_node(root_node, key));
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator pointing to the first element in the
+ /// container whose key is not considered to go after the key provided
+ /// or end() if all keys are considered to go after the key provided.
+ ///\return An const_iterator pointing to the element after key or end()
+ //*********************************************************************
+ const_iterator upper_bound(const key_value_parameter_t& key) const
+ {
+ return const_iterator(*this, find_upper_node(root_node, key));
+ }
+
+ protected:
+
+ //*************************************************************************
+ /// Constructor.
+ //*************************************************************************
+ iset(ipool<Data_Node>& node_pool, size_t max_size_)
+ : set_base(max_size_)
+ , p_node_pool(&node_pool)
+ {
+ }
+
+ //*************************************************************************
+ /// Initialise the set.
+ //*************************************************************************
+ void initialise()
+ {
+ if (!empty())
+ {
+ p_node_pool->release_all();
+ }
+
+ current_size = 0;
+ root_node = nullptr;
+ }
+
+ private:
+
+ //*************************************************************************
+ /// Allocate a Data_Node.
+ //*************************************************************************
+ Data_Node& allocate_data_node(value_type value) const
+ {
+ return *(p_node_pool->allocate(Data_Node(value)));
+ }
+
+ //*************************************************************************
+ /// Destroy a Data_Node.
+ //*************************************************************************
+ void destroy_data_node(Data_Node& node) const
+ {
+ p_node_pool->release(&node);
+ }
+
+ //*************************************************************************
+ /// Find the value matching the node provided
+ //*************************************************************************
+ Node* find_node(Node* position, const key_value_parameter_t& key)
+ {
+ Node* found = position;
+ while (found)
+ {
+ // Downcast found to Data_Node class for comparison and other operations
+ Data_Node& found_data_node = iset::data_cast(*found);
+
+ // Compare the node value to the current position value
+ if (node_comp(key, found_data_node))
+ {
+ // Keep searching for the node on the left
+ found = found->children[kLeft];
+ }
+ else if (node_comp(found_data_node, key))
+ {
+ // Keep searching for the node on the right
+ found = found->children[kRight];
+ }
+ else
+ {
+ // Node that matches the key provided was found, exit loop
+ break;
+ }
+ }
+
+ // Return the node found (might be nullptr)
+ return found;
+ }
+
+ //*************************************************************************
+ /// Find the value matching the node provided
+ //*************************************************************************
+ const Node* find_node(const Node* position, const key_value_parameter_t& key) const
+ {
+ const Node* found = position;
+ while (found)
+ {
+ // Downcast found to Data_Node class for comparison and other operations
+ const Data_Node& found_data_node = iset::data_cast(*found);
+
+ // Compare the node value to the current position value
+ if (node_comp(key, found_data_node))
+ {
+ // Keep searching for the node on the left
+ found = found->children[kLeft];
+ }
+ else if (node_comp(found_data_node, key))
+ {
+ // Keep searching for the node on the right
+ found = found->children[kRight];
+ }
+ else
+ {
+ // Node that matches the key provided was found, exit loop
+ break;
+ }
+ }
+
+ // Return the node found (might be nullptr)
+ return found;
+ }
+
+ //*************************************************************************
+ /// Find the reference node matching the node provided
+ //*************************************************************************
+ Node*& find_node(Node*& position, const Node* node)
+ {
+ Node* found = position;
+ while (found)
+ {
+ if (found->children[kLeft] == node)
+ {
+ return found->children[kLeft];
+ }
+ else if (found->children[kRight] == node)
+ {
+ return found->children[kRight];
+ }
+ else
+ {
+ // Downcast found to Data_Node class for comparison and other operations
+ Data_Node& found_data_node = iset::data_cast(*found);
+ const Data_Node& data_node = iset::data_cast(*node);
+
+ // Compare the node value to the current position value
+ if (node_comp(data_node, found_data_node))
+ {
+ // Keep searching for the node on the left
+ found = found->children[kLeft];
+ }
+ else if (node_comp(found_data_node, data_node))
+ {
+ // Keep searching for the node on the right
+ found = found->children[kRight];
+ }
+ else
+ {
+ // Return position provided (it matches the node)
+ return position;
+ }
+ }
+ }
+
+ // Return root node if nothing was found
+ return root_node;
+ }
+
+ //*************************************************************************
+ /// Find the parent node that contains the node provided in its left or
+ /// right tree
+ //*************************************************************************
+ Node* find_parent_node(Node* position, const Node* node)
+ {
+ // Default to no parent node found
+ Node* found = nullptr;
+
+ // If the position provided is the same as the node then there is no parent
+ if (position && node && position != node)
+ {
+ while (position)
+ {
+ // Is this position not the parent of the node we are looking for?
+ if (position->children[kLeft] != node &&
+ position->children[kRight] != node)
+ {
+ // Downcast node and position to Data_Node references for key comparisons
+ const Data_Node& node_data_node = iset::data_cast(*node);
+ Data_Node& position_data_node = iset::data_cast(*position);
+ // Compare the node value to the current position value
+ if (node_comp(node_data_node, position_data_node))
+ {
+ // Keep looking for parent on the left
+ position = position->children[kLeft];
+ }
+ else if (node_comp(position_data_node, node_data_node))
+ {
+ // Keep looking for parent on the right
+ position = position->children[kRight];
+ }
+ }
+ else
+ {
+ // Return the current position as the parent node found
+ found = position;
+
+ // Parent node found, exit loop
+ break;
+ }
+ }
+ }
+
+ // Return the parent node found (might be nullptr)
+ return found;
+ }
+
+ //*************************************************************************
+ /// Find the parent node that contains the node provided in its left or
+ /// right tree
+ //*************************************************************************
+ const Node* find_parent_node(const Node* position, const Node* node) const
+ {
+ // Default to no parent node found
+ const Node* found = nullptr;
+
+ // If the position provided is the same as the node then there is no parent
+ if (position && node && position != node)
+ {
+ while (position)
+ {
+ // Is this position not the parent of the node we are looking for?
+ if (position->children[kLeft] != node &&
+ position->children[kRight] != node)
+ {
+ // Downcast node and position to Data_Node references for key comparisons
+ const Data_Node& node_data_node = iset::data_cast(*node);
+ const Data_Node& position_data_node = iset::data_cast(*position);
+ // Compare the node value to the current position value
+ if (node_comp(node_data_node, position_data_node))
+ {
+ // Keep looking for parent on the left
+ position = position->children[kLeft];
+ }
+ else if (node_comp(position_data_node, node_data_node))
+ {
+ // Keep looking for parent on the right
+ position = position->children[kRight];
+ }
+ }
+ else
+ {
+ // Return the current position as the parent node found
+ found = position;
+
+ // Parent node found, exit loop
+ break;
+ }
+ }
+ }
+
+ // Return the parent node found (might be nullptr)
+ return found;
+ }
+
+ //*************************************************************************
+ /// Find the node whose key is not considered to go before the key provided
+ //*************************************************************************
+ Node* find_lower_node(Node* position, const key_value_parameter_t& key) const
+ {
+ // Something at this position? keep going
+ Node* lower_node = position;
+ while (lower_node)
+ {
+ // Downcast lower node to Data_Node reference for key comparisons
+ Data_Node& data_node = iset::data_cast(*lower_node);
+ // Compare the key value to the current lower node key value
+ if (node_comp(key, data_node))
+ {
+ if (lower_node->children[kLeft])
+ {
+ lower_node = lower_node->children[kLeft];
+ }
+ else
+ {
+ // Found lowest node
+ break;
+ }
+ }
+ else if (node_comp(data_node, key))
+ {
+ lower_node = lower_node->children[kRight];
+ }
+ else
+ {
+ // Found equal node
+ break;
+ }
+ }
+
+ // Return the lower_node position found
+ return lower_node;
+ }
+
+ //*************************************************************************
+ /// Find the node whose key is considered to go after the key provided
+ //*************************************************************************
+ Node* find_upper_node(Node* position, const key_value_parameter_t& key) const
+ {
+ // Keep track of parent of last upper node
+ Node* upper_node = nullptr;
+ // Start with position provided
+ Node* node = position;
+ while (node)
+ {
+ // Downcast position to Data_Node reference for key comparisons
+ Data_Node& data_node = iset::data_cast(*node);
+ // Compare the key value to the current upper node key value
+ if (node_comp(key, data_node))
+ {
+ upper_node = node;
+ node = node->children[kLeft];
+ }
+ else if (node_comp(data_node, key))
+ {
+ node = node->children[kRight];
+ }
+ else if (node->children[kRight])
+ {
+ upper_node = find_limit_node(node->children[kRight], kLeft);
+ break;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ // Return the upper node position found (might be nullptr)
+ return upper_node;
+ }
+
+ //*************************************************************************
+ /// Insert a node.
+ //*************************************************************************
+ Node* insert_node(Node*& position, Data_Node& node)
+ {
+ // Find the location where the node belongs
+ Node* found = position;
+
+ // Was position provided not empty? then find where the node belongs
+ if (position)
+ {
+ // Find the critical parent node (default to nullptr)
+ Node* critical_parent_node = nullptr;
+ Node* critical_node = root_node;
+
+ while (found)
+ {
+ // Search for critical weight node (all nodes whose weight factor
+ // is set to kNeither (balanced)
+ if (kNeither != found->weight)
+ {
+ critical_node = found;
+ }
+
+ // Downcast found to Data_Node class for comparison and other operations
+ Data_Node& found_data_node = iset::data_cast(*found);
+
+ // Is the node provided to the left of the current position?
+ if (node_comp(node, found_data_node))
+ {
+ // Update direction taken to insert new node in parent node
+ found->dir = kLeft;
+ }
+ // Is the node provided to the right of the current position?
+ else if (node_comp(found_data_node, node))
+ {
+ // Update direction taken to insert new node in parent node
+ found->dir = kRight;
+ }
+ else
+ {
+ // Update direction taken to insert new node in parent node
+ found->dir = kNeither;
+
+ // Clear critical node value to skip weight step below
+ critical_node = nullptr;
+
+ // Destroy the node provided (its a duplicate)
+ destroy_data_node(node);
+
+ // Exit loop, duplicate node found
+ break;
+ }
+
+ // Is there a child of this parent node?
+ if (found->children[found->dir])
+ {
+ // Will this node be the parent of the next critical node whose
+ // weight factor is set to kNeither (balanced)?
+ if (kNeither != found->children[found->dir]->weight)
+ {
+ critical_parent_node = found;
+ }
+
+ // Keep looking for empty spot to insert new node
+ found = found->children[found->dir];
+ }
+ else
+ {
+ // Attatch node to right
+ attach_node(found->children[found->dir], node);
+
+ // Return newly added node
+ found = found->children[found->dir];
+
+ // Exit loop
+ break;
+ }
+ }
+
+ // Was a critical node found that should be checked for balance?
+ if (critical_node)
+ {
+ if (critical_parent_node == nullptr && critical_node == root_node)
+ {
+ balance_node(root_node);
+ }
+ else if (critical_parent_node == nullptr && critical_node == position)
+ {
+ balance_node(position);
+ }
+ else
+ {
+ balance_node(critical_parent_node->children[critical_parent_node->dir]);
+ }
+ }
+ }
+ else
+ {
+ // Attatch node to current position
+ attach_node(position, node);
+
+ // Return newly added node at current position
+ found = position;
+ }
+
+ // Return the node found (might be nullptr)
+ return found;
+ }
+
+ //*************************************************************************
+ /// Find the next node in sequence from the node provided
+ //*************************************************************************
+ void next_node(Node*&position)
+ {
+ if (position)
+ {
+ // Is there a tree on the right? then find the minimum of that tree
+ if (position->children[kRight])
+ {
+ // Return minimum node found
+ position = find_limit_node(position->children[kRight], kLeft);
+ }
+ // Otherwise find the parent of this node
+ else
+ {
+ // Start with current position as parent
+ Node* parent = position;
+ do {
+ // Update current position as previous parent
+ position = parent;
+ // Find parent of current position
+ parent = find_parent_node(root_node, position);
+ // Repeat while previous position was on right side of parent tree
+ } while (parent && parent->children[kRight] == position);
+
+ // Set parent node as the next position
+ position = parent;
+ }
+ }
+ }
+
+ //*************************************************************************
+ /// Find the next node in sequence from the node provided
+ //*************************************************************************
+ void next_node(const Node*& position) const
+ {
+ if (position)
+ {
+ // Is there a tree on the right? then find the minimum of that tree
+ if (position->children[kRight])
+ {
+ // Return minimum node found
+ position = find_limit_node(position->children[kRight], kLeft);
+ }
+ // Otherwise find the parent of this node
+ else
+ {
+ // Start with current position as parent
+ const Node* parent = position;
+ do {
+ // Update current position as previous parent
+ position = parent;
+ // Find parent of current position
+ parent = find_parent_node(root_node, position);
+ // Repeat while previous position was on right side of parent tree
+ } while (parent && parent->children[kRight] == position);
+
+ // Set parent node as the next position
+ position = parent;
+ }
+ }
+ }
+
+ //*************************************************************************
+ /// Find the previous node in sequence from the node provided
+ //*************************************************************************
+ void prev_node(Node*&position)
+ {
+ // If starting at the terminal end, the previous node is the maximum node
+ // from the root
+ if (!position)
+ {
+ position = find_limit_node(root_node, kRight);
+ }
+ else
+ {
+ // Is there a tree on the left? then find the maximum of that tree
+ if (position->children[kLeft])
+ {
+ // Return maximum node found
+ position = find_limit_node(position->children[kLeft], kRight);
+ }
+ // Otherwise find the parent of this node
+ else
+ {
+ // Start with current position as parent
+ Node* parent = position;
+ do {
+ // Update current position as previous parent
+ position = parent;
+ // Find parent of current position
+ parent = find_parent_node(root_node, position);
+ // Repeat while previous position was on left side of parent tree
+ } while (parent && parent->children[kLeft] == position);
+
+ // Set parent node as the next position
+ position = parent;
+ }
+ }
+ }
+
+ //*************************************************************************
+ /// Find the previous node in sequence from the node provided
+ //*************************************************************************
+ void prev_node(const Node*& position) const
+ {
+ // If starting at the terminal end, the previous node is the maximum node
+ // from the root
+ if (!position)
+ {
+ position = find_limit_node(root_node, kRight);
+ }
+ else
+ {
+ // Is there a tree on the left? then find the maximum of that tree
+ if (position->children[kLeft])
+ {
+ // Return maximum node found
+ position = find_limit_node(position->children[kLeft], kRight);
+ }
+ // Otherwise find the parent of this node
+ else
+ {
+ // Start with current position as parent
+ const Node* parent = position;
+ do {
+ // Update current position as previous parent
+ position = parent;
+ // Find parent of current position
+ parent = find_parent_node(root_node, position);
+ // Repeat while previous position was on left side of parent tree
+ } while (parent && parent->children[kLeft] == position);
+
+ // Set parent node as the next position
+ position = parent;
+ }
+ }
+ }
+
+ //*************************************************************************
+ /// Remove the node specified from somewhere starting at the position
+ /// provided
+ //*************************************************************************
+ Node* remove_node(Node*& position, const key_value_parameter_t& key)
+ {
+ // Step 1: Find the target node that matches the key provided, the
+ // replacement node (might be the same as target node), and the critical
+ // node to start rebalancing the tree from (up to the replacement node)
+ Node* found_parent = nullptr;
+ Node* found = nullptr;
+ Node* replace_parent = nullptr;
+ Node* replace = position;
+ Node* balance_parent = nullptr;
+ Node* balance = root_node;
+ while (replace)
+ {
+ // Downcast found to Data_Node class for comparison and other operations
+ Data_Node& replace_data_node = iset::data_cast(*replace);
+
+ // Compare the key provided to the replace data node key
+ if (node_comp(key, replace_data_node))
+ {
+ // Update the direction to the target/replace node
+ replace->dir = kLeft;
+ }
+ else if (node_comp(replace_data_node, key))
+ {
+ // Update the direction to the target/replace node
+ replace->dir = kRight;
+ }
+ else
+ {
+ // Update the direction to the replace node (target node found here)
+ replace->dir = replace->children[kLeft] ? kLeft : kRight;
+
+ // Note the target node was found (and its parent)
+ found_parent = replace_parent;
+ found = replace;
+ }
+ // Replacement node found if its missing a child in the replace->dir
+ // value set above
+ if (replace->children[replace->dir] == nullptr)
+ {
+ // Exit loop once replace node is found (target might not have been)
+ break;
+ }
+
+ // If replacement node weight is kNeither or we are taking the shorter
+ // path of replacement node and our sibling (on longer path) is
+ // balanced then we need to update the balance node to match this
+ // replacement node but all our ancestors will not require rebalancing
+ if ((replace->weight == kNeither) ||
+ (replace->weight == (1 - replace->dir) &&
+ replace->children[1 - replace->dir]->weight == kNeither))
+ {
+ // Update balance node (and its parent) to replacement node
+ balance_parent = replace_parent;
+ balance = replace;
+ }
+
+ // Keep searching for the replacement node
+ replace_parent = replace;
+ replace = replace->children[replace->dir];
+ }
+
+ // If target node was found, proceed with rebalancing and replacement
+ if (found)
+ {
+ // Step 2: Update weights from critical node to replacement parent node
+ while (balance)
+ {
+ if (balance->children[balance->dir] == nullptr)
+ {
+ break;
+ }
+
+ if (balance->weight == kNeither)
+ {
+ balance->weight = 1 - balance->dir;
+ }
+ else if (balance->weight == balance->dir)
+ {
+ balance->weight = kNeither;
+ }
+ else
+ {
+ int weight = balance->children[1 - balance->dir]->weight;
+ // Perform a 3 node rotation if weight is same as balance->dir
+ if (weight == balance->dir)
+ {
+ // Is the root node being rebalanced (no parent)
+ if (balance_parent == nullptr)
+ {
+ rotate_3node(root_node, 1 - balance->dir,
+ balance->children[1 - balance->dir]->children[balance->dir]->weight);
+ }
+ else
+ {
+ rotate_3node(balance_parent->children[balance_parent->dir], 1 - balance->dir,
+ balance->children[1 - balance->dir]->children[balance->dir]->weight);
+ }
+ }
+ // Already balanced, rebalance and make it heavy in opposite
+ // direction of the node being removed
+ else if (weight == kNeither)
+ {
+ // Is the root node being rebalanced (no parent)
+ if (balance_parent == nullptr)
+ {
+ rotate_2node(root_node, 1 - balance->dir);
+ root_node->weight = balance->dir;
+ }
+ else
+ {
+ rotate_2node(balance_parent->children[balance_parent->dir], 1 - balance->dir);
+ balance_parent->children[balance_parent->dir]->weight = balance->dir;
+ }
+ // Update balance node weight in opposite direction of node removed
+ balance->weight = 1 - balance->dir;
+ }
+ // Rebalance and leave it balanced
+ else
+ {
+ // Is the root node being rebalanced (no parent)
+ if (balance_parent == nullptr)
+ {
+ rotate_2node(root_node, 1 - balance->dir);
+ }
+ else
+ {
+ rotate_2node(balance_parent->children[balance_parent->dir], 1 - balance->dir);
+ }
+ }
+
+ // Is balance node the same as the target node found? then update
+ // its parent after the rotation performed above
+ if (balance == found)
+ {
+ if (balance_parent)
+ {
+ found_parent = balance_parent->children[balance_parent->dir];
+ // Update dir since it is likely stale
+ found_parent->dir = found_parent->children[kLeft] == found ? kLeft : kRight;
+ }
+ else
+ {
+ found_parent = root_node;
+ root_node->dir = root_node->children[kLeft] == found ? kLeft : kRight;
+ }
+ }
+ }
+
+ // Next balance node to consider
+ balance_parent = balance;
+ balance = balance->children[balance->dir];
+ } // while(balance)
+
+ // Step 3: Swap found node with replacement node
+ if (found_parent)
+ {
+ // Handle traditional case
+ detach_node(found_parent->children[found_parent->dir],
+ replace_parent->children[replace_parent->dir]);
+ }
+ // Handle root node removal
+ else
+ {
+ // Valid replacement node for root node being removed?
+ if (replace_parent)
+ {
+ detach_node(root_node, replace_parent->children[replace_parent->dir]);
+ }
+ else
+ {
+ // Target node and replacement node are both root node
+ detach_node(root_node, root_node);
+ }
+ }
+
+ // Downcast found into data node
+ Data_Node& found_data_node = iset::data_cast(*found);
+
+ // One less.
+ --current_size;
+
+ // Destroy the node removed
+ destroy_data_node(found_data_node);
+ } // if(found)
+
+ // Return node found (might be nullptr)
+ return found;
+ }
+
+ // Disable copy construction.
+ iset(const iset&);
+ };
+}
+
+//***************************************************************************
+/// Equal operator.
+///\param lhs Reference to the first lookup.
+///\param rhs Reference to the second lookup.
+///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
+///\ingroup lookup
+//***************************************************************************
+template <typename T, typename TCompare>
+bool operator ==(const etl::iset<T, TCompare>& lhs, const etl::iset<T, TCompare>& rhs)
+{
+ return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin());
+}
+
+//***************************************************************************
+/// Not equal operator.
+///\param lhs Reference to the first lookup.
+///\param rhs Reference to the second lookup.
+///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
+///\ingroup lookup
+//***************************************************************************
+template <typename T, typename TCompare>
+bool operator !=(const etl::iset<T, TCompare>& lhs, const etl::iset<T, TCompare>& rhs)
+{
+ return !(lhs == rhs);
+}
+
+//*************************************************************************
+/// Less than operator.
+///\param lhs Reference to the first list.
+///\param rhs Reference to the second list.
+///\return <b>true</b> if the first list is lexicographically less than the
+/// second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename T, typename TCompare>
+bool operator <(const etl::iset<T, TCompare>& lhs, const etl::iset<T, TCompare>& rhs)
+{
+ return std::lexicographical_compare(lhs.begin(),
+ lhs.end(),
+ rhs.begin(),
+ rhs.end());
+}
+
+//*************************************************************************
+/// Greater than operator.
+///\param lhs Reference to the first list.
+///\param rhs Reference to the second list.
+///\return <b>true</b> if the first list is lexicographically greater than the
+/// second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename T, typename TCompare>
+bool operator >(const etl::iset<T, TCompare>& lhs, const etl::iset<T, TCompare>& rhs)
+{
+ return (rhs < lhs);
+}
+
+//*************************************************************************
+/// Less than or equal operator.
+///\param lhs Reference to the first list.
+///\param rhs Reference to the second list.
+///\return <b>true</b> if the first list is lexicographically less than or equal
+/// to the second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename T, typename TCompare>
+bool operator <=(const etl::iset<T, TCompare>& lhs, const etl::iset<T, TCompare>& rhs)
+{
+ return !(lhs > rhs);
+}
+
+//*************************************************************************
+/// Greater than or equal operator.
+///\param lhs Reference to the first list.
+///\param rhs Reference to the second list.
+///\return <b>true</b> if the first list is lexicographically greater than or
+/// equal to the second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename T, typename TCompare>
+bool operator >=(const etl::iset<T, TCompare>& lhs, const etl::iset<T, TCompare>& rhs)
+{
+ return !(lhs < rhs);
+}
+
+#ifdef ETL_COMPILER_MICROSOFT
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#undef __ETL_IN_ISET_H__
+
+#endif
diff --git a/lib/etl/istack.h b/lib/etl/istack.h
new file mode 100644
index 0000000..35e8107
--- /dev/null
+++ b/lib/etl/istack.h
@@ -0,0 +1,197 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_ISTACK__
+#define __ETL_ISTACK__
+#define __ETL_IN_ISTACK_H__
+
+#include <stddef.h>
+
+#include "private/stack_base.h"
+#include "type_traits.h"
+#include "parameter_type.h"
+#include "error_handler.h"
+
+namespace etl
+{
+ //***************************************************************************
+ ///\ingroup stack
+ ///\brief This is the base for all stacks that contain a particular type.
+ ///\details Normally a reference to this type will be taken from a derived stack.
+ ///\code
+ /// etl::stack<int, 10> myQueue;
+ /// etl::istack<int>& iQueue = myQueue;
+ ///\endcode
+ /// \warning This stack cannot be used for concurrent access from multiple threads.
+ /// \tparam T The type of value that the stack holds.
+ //***************************************************************************
+ template <typename T>
+ class istack : public stack_base
+ {
+ public:
+
+ typedef T value_type; ///< The type stored in the stack.
+ typedef T& reference; ///< A reference to the type used in the stack.
+ typedef const T& const_reference; ///< A const reference to the type used in the stack.
+ typedef T* pointer; ///< A pointer to the type used in the stack.
+ typedef const T* const_pointer; ///< A const pointer to the type used in the stack.
+ typedef stack_base::size_type size_type; ///< The type used for determining the size of the stack.
+
+ private:
+
+ typedef typename parameter_type<T>::type parameter_t;
+
+ public:
+
+ //*************************************************************************
+ /// Gets a reference to the value at the top of the stack.<br>
+ /// \return A reference to the value at the top of the stack.
+ //*************************************************************************
+ reference top()
+ {
+ return p_buffer[top_index];
+ }
+
+ //*************************************************************************
+ /// Adds a value to the stack.
+ /// If asserts or exceptions are enabled, throws an etl::stack_full if the stack is already full.
+ ///\param value The value to push to the stack.
+ //*************************************************************************
+ void push(parameter_t value)
+ {
+#if defined(ETL_CHECK_PUSH_POP)
+ ETL_ASSERT(!full(), ETL_ERROR(stack_full));
+#endif
+ top_index = current_size++;
+ new(&p_buffer[top_index]) T(value);
+ }
+
+ //*************************************************************************
+ /// Allows a possibly more efficient 'push' by moving to the next input value
+ /// and returning a reference to it.
+ /// This may eliminate a copy by allowing direct construction in-place.<br>
+ /// If asserts or exceptions are enabled, throws an etl::stack_full if the stack is already full.
+ /// \return A reference to the position to 'push' to.
+ //*************************************************************************
+ reference push()
+ {
+#if defined(ETL_CHECK_PUSH_POP)
+ ETL_ASSERT(!full(), ETL_ERROR(stack_full));
+#endif
+ top_index = current_size++;
+ new(&p_buffer[top_index]) T();
+
+ return p_buffer[top_index];
+ }
+
+ //*************************************************************************
+ /// Gets a const reference to the value at the top of the stack.<br>
+ /// \return A const reference to the value at the top of the stack.
+ //*************************************************************************
+ const_reference top() const
+ {
+ return p_buffer[top_index];
+ }
+
+ //*************************************************************************
+ /// Clears the stack to the empty state.
+ //*************************************************************************
+ void clear()
+ {
+ while (current_size > 0)
+ {
+ p_buffer[top_index].~T();
+ --top_index;
+ --current_size;
+ }
+ }
+
+ //*************************************************************************
+ /// Removes the oldest item from the top of the stack.
+ /// Does nothing if the stack is already empty.
+ //*************************************************************************
+ void pop()
+ {
+#if defined(ETL_CHECK_PUSH_POP)
+ ETL_ASSERT(!empty(), ETL_ERROR(stack_empty));
+#endif
+ p_buffer[top_index].~T();
+ --top_index;
+ --current_size;
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ istack& operator = (const istack& rhs)
+ {
+ if (&rhs != this)
+ {
+ clone(rhs);
+ }
+
+ return *this;
+ }
+
+ protected:
+
+ //*************************************************************************
+ /// Make this a clone of the supplied stack
+ //*************************************************************************
+ void clone(const istack& other)
+ {
+ size_t index = 0;
+
+ for (size_t i = 0; i < other.size(); ++i)
+ {
+ push(other.p_buffer[index++]);
+ }
+ }
+
+ //*************************************************************************
+ /// The constructor that is called from derived classes.
+ //*************************************************************************
+ istack(T* p_buffer, size_type max_size)
+ : stack_base(max_size),
+ p_buffer(p_buffer)
+ {
+ }
+
+ private:
+
+ // Disable copy construction.
+ istack(const istack&);
+
+ T* p_buffer; ///< The internal buffer.
+ };
+}
+
+#undef __ETL_IN_ISTACK_H__
+#endif
diff --git a/lib/etl/iunordered_map.h b/lib/etl/iunordered_map.h
new file mode 100644
index 0000000..e8447fa
--- /dev/null
+++ b/lib/etl/iunordered_map.h
@@ -0,0 +1,1271 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_IUNORDERED_MAP__
+#define __ETL_IUNORDERED_MAP__
+
+#include <iterator>
+#include <algorithm>
+#include <functional>
+#include <utility>
+#include <stddef.h>
+
+#include "type_traits.h"
+#include "parameter_type.h"
+#include "hash.h"
+#include "nullptr.h"
+#include "ipool.h"
+#include "ivector.h"
+#include "error_handler.h"
+#include "intrusive_forward_list.h"
+#include "exception.h"
+#include "error_handler.h"
+
+#undef ETL_FILE
+#define ETL_FILE "16"
+
+namespace etl
+{
+ //***************************************************************************
+ /// Exception for the unordered_map.
+ ///\ingroup unordered_map
+ //***************************************************************************
+ class unordered_map_exception : public exception
+ {
+ public:
+
+ unordered_map_exception(string_type what, string_type file_name, numeric_type line_number)
+ : exception(what, file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// Full exception for the unordered_map.
+ ///\ingroup unordered_map
+ //***************************************************************************
+ class unordered_map_full : public unordered_map_exception
+ {
+ public:
+
+ unordered_map_full(string_type file_name, numeric_type line_number)
+ : unordered_map_exception(ETL_ERROR_TEXT("unordered_map:full", ETL_FILE"A"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// Out of range exception for the unordered_map.
+ ///\ingroup unordered_map
+ //***************************************************************************
+ class unordered_map_out_of_range : public unordered_map_exception
+ {
+ public:
+
+ unordered_map_out_of_range(string_type file_name, numeric_type line_number)
+ : unordered_map_exception(ETL_ERROR_TEXT("unordered_map:range", ETL_FILE"B"), file_name, line_number)
+ {}
+ };
+
+ //***************************************************************************
+ /// Iterator exception for the unordered_map.
+ ///\ingroup unordered_map
+ //***************************************************************************
+ class unordered_map_iterator : public unordered_map_exception
+ {
+ public:
+
+ unordered_map_iterator(string_type file_name, numeric_type line_number)
+ : unordered_map_exception(ETL_ERROR_TEXT("unordered_map:iterator", ETL_FILE"C"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// The base class for specifically sized unordered_map.
+ /// Can be used as a reference type for all unordered_map containing a specific type.
+ ///\ingroup unordered_map
+ //***************************************************************************
+ template <typename TKey, typename T, typename THash = etl::hash<TKey>, typename TKeyEqual = std::equal_to<TKey> >
+ class iunordered_map
+ {
+ public:
+
+ typedef std::pair<const TKey, T> value_type;
+
+ typedef TKey key_type;
+ typedef T mapped_type;
+ typedef THash hasher;
+ typedef TKeyEqual key_equal;
+ typedef value_type& reference;
+ typedef const value_type& const_reference;
+ typedef value_type* pointer;
+ typedef const value_type* const_pointer;
+ typedef size_t size_type;
+
+
+ typedef typename parameter_type<TKey>::type key_value_parameter_t;
+
+ typedef etl::forward_link<0> link_t; // Default link.
+
+ // The nodes that store the elements.
+ struct node_t : public link_t
+ {
+ node_t(const value_type& key_value_pair)
+ : key_value_pair(key_value_pair)
+ {
+ }
+
+ value_type key_value_pair;
+ };
+
+ private:
+
+ typedef etl::intrusive_forward_list<node_t, link_t> bucket_t;
+ typedef etl::ipool<node_t> pool_t;
+ typedef etl::ivector<bucket_t> bucket_list_t;
+
+ typedef typename bucket_list_t::iterator bucket_list_iterator;
+
+ public:
+
+ // Local iterators iterate over one bucket.
+ typedef typename bucket_t::iterator local_iterator;
+ typedef typename bucket_t::const_iterator local_const_iterator;
+
+ //*********************************************************************
+ class iterator : public std::iterator<std::forward_iterator_tag, T>
+ {
+ public:
+
+ typedef typename iunordered_map::value_type value_type;
+ typedef typename iunordered_map::key_type key_type;
+ typedef typename iunordered_map::mapped_type mapped_type;
+ typedef typename iunordered_map::hasher hasher;
+ typedef typename iunordered_map::key_equal key_equal;
+ typedef typename iunordered_map::reference reference;
+ typedef typename iunordered_map::const_reference const_reference;
+ typedef typename iunordered_map::pointer pointer;
+ typedef typename iunordered_map::const_pointer const_pointer;
+ typedef typename iunordered_map::size_type size_type;
+
+ friend class iunordered_map;
+
+ //*********************************
+ iterator()
+ {
+ }
+
+ //*********************************
+ iterator(const iterator& other)
+ : ibuckets_end(other.ibuckets_end),
+ ibucket(other.ibucket),
+ inode(other.inode)
+ {
+ }
+
+ //*********************************
+ iterator& operator ++()
+ {
+ ++inode;
+
+ // The end of this node list?
+ if (inode == ibucket->end())
+ {
+ // Search for the next non-empty bucket.
+ ++ibucket;
+ while ((ibucket != ibuckets_end) && (ibucket->empty()))
+ {
+ ++ibucket;
+ }
+
+ // If not past the end, get the first node in the bucket.
+ if (ibucket != ibuckets_end)
+ {
+ inode = ibucket->begin();
+ }
+ }
+
+ return *this;
+ }
+
+ //*********************************
+ iterator operator ++(int)
+ {
+ iterator temp(*this);
+ operator++();
+ return temp;
+ }
+
+ //*********************************
+ iterator operator =(const iterator& other)
+ {
+ ibuckets_end = other.ibuckets_end;
+ ibucket = other.ibucket;
+ inode = other.inode;
+ return *this;
+ }
+
+ //*********************************
+ std::pair<const TKey, T> operator *()
+ {
+ return inode->key_value_pair;
+ }
+
+ //*********************************
+ const_reference operator *() const
+ {
+ return inode->key_value_pair;
+ }
+
+ //*********************************
+ pointer operator &()
+ {
+ return &(inode->key_value_pair);
+ }
+
+ //*********************************
+ const_pointer operator &() const
+ {
+ return &(inode->key_value_pair);
+ }
+
+ //*********************************
+ pointer operator ->()
+ {
+ return &(inode->key_value_pair);
+ }
+
+ //*********************************
+ const_pointer operator ->() const
+ {
+ return &(inode->key_value_pair);
+ }
+
+ //*********************************
+ friend bool operator == (const iterator& lhs, const iterator& rhs)
+ {
+ return lhs.compare(rhs);
+ }
+
+ //*********************************
+ friend bool operator != (const iterator& lhs, const iterator& rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+ private:
+
+ //*********************************
+ iterator(bucket_list_iterator ibuckets_end, bucket_list_iterator ibucket, local_iterator inode)
+ : ibuckets_end(ibuckets_end),
+ ibucket(ibucket),
+ inode(inode)
+ {
+ }
+
+ //*********************************
+ bool compare(const iterator& rhs) const
+ {
+ return rhs.inode == inode;
+ }
+
+ //*********************************
+ bucket_t& get_bucket()
+ {
+ return *ibucket;
+ }
+
+ //*********************************
+ bucket_list_iterator& get_bucket_list_iterator()
+ {
+ return ibucket;
+ }
+
+ //*********************************
+ local_iterator get_local_iterator()
+ {
+ return inode;
+ }
+
+ bucket_list_iterator ibuckets_end;
+ bucket_list_iterator ibucket;
+ local_iterator inode;
+ };
+
+ //*********************************************************************
+ class const_iterator : public std::iterator<std::forward_iterator_tag, const T>
+ {
+ public:
+
+ typedef typename iunordered_map::value_type value_type;
+ typedef typename iunordered_map::key_type key_type;
+ typedef typename iunordered_map::mapped_type mapped_type;
+ typedef typename iunordered_map::hasher hasher;
+ typedef typename iunordered_map::key_equal key_equal;
+ typedef typename iunordered_map::reference reference;
+ typedef typename iunordered_map::const_reference const_reference;
+ typedef typename iunordered_map::pointer pointer;
+ typedef typename iunordered_map::const_pointer const_pointer;
+ typedef typename iunordered_map::size_type size_type;
+
+ friend class iunordered_map;
+ friend class iterator;
+
+ //*********************************
+ const_iterator()
+ {
+ }
+
+ //*********************************
+ const_iterator(const typename iunordered_map::iterator& other)
+ : ibuckets_end(other.ibuckets_end),
+ ibucket(other.ibucket),
+ inode(other.inode)
+ {
+ }
+
+ //*********************************
+ const_iterator(const const_iterator& other)
+ : ibuckets_end(other.ibuckets_end),
+ ibucket(other.ibucket),
+ inode(other.inode)
+ {
+ }
+
+ //*********************************
+ const_iterator& operator ++()
+ {
+ ++inode;
+
+ // The end of this node list?
+ if (inode == ibucket->end())
+ {
+ // Search for the next non-empty bucket.
+
+ ++ibucket;
+ while ((ibucket != ibuckets_end) && (ibucket->empty()))
+ {
+ ++ibucket;
+ }
+
+ // If not past the end, get the first node in the bucket.
+ if (ibucket != ibuckets_end)
+ {
+ inode = ibucket->begin();
+ }
+ }
+
+ return *this;
+ }
+
+ //*********************************
+ const_iterator operator ++(int)
+ {
+ const_iterator temp(*this);
+ operator++();
+ return temp;
+ }
+
+ //*********************************
+ const_iterator operator =(const const_iterator& other)
+ {
+ ibuckets_end = other.ibuckets_end;
+ ibucket = other.ibucket;
+ inode = other.inode;
+ return *this;
+ }
+
+ //*********************************
+ const_reference operator *() const
+ {
+ return inode->key_value_pair;
+ }
+
+ //*********************************
+ const_pointer operator &() const
+ {
+ return &(inode->key_value_pair);
+ }
+
+ //*********************************
+ const_pointer operator ->() const
+ {
+ return &(inode->key_value_pair);
+ }
+
+ //*********************************
+ friend bool operator == (const const_iterator& lhs, const const_iterator& rhs)
+ {
+ return lhs.compare(rhs);
+ }
+
+ //*********************************
+ friend bool operator != (const const_iterator& lhs, const const_iterator& rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+ private:
+
+ //*********************************
+ const_iterator(bucket_list_iterator ibuckets_end, bucket_list_iterator ibucket, local_iterator inode)
+ : ibuckets_end(ibuckets_end),
+ ibucket(ibucket),
+ inode(inode)
+ {
+ }
+
+ //*********************************
+ bool compare(const const_iterator& rhs) const
+ {
+ return rhs.inode == inode;
+ }
+
+ //*********************************
+ bucket_t& get_bucket()
+ {
+ return *ibucket;
+ }
+
+ //*********************************
+ bucket_list_iterator& get_bucket_list_iterator()
+ {
+ return ibucket;
+ }
+
+ //*********************************
+ local_iterator get_local_iterator()
+ {
+ return inode;
+ }
+
+ bucket_list_iterator ibuckets_end;
+ bucket_list_iterator ibucket;
+ local_iterator inode;
+ };
+
+ typedef typename std::iterator_traits<iterator>::difference_type difference_type;
+
+ //*********************************************************************
+ /// Returns an iterator to the beginning of the unordered_map.
+ ///\return An iterator to the beginning of the unordered_map.
+ //*********************************************************************
+ iterator begin()
+ {
+ return iterator(pbuckets->end(), first, first->begin());
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the beginning of the unordered_map.
+ ///\return A const iterator to the beginning of the unordered_map.
+ //*********************************************************************
+ const_iterator begin() const
+ {
+ return const_iterator(pbuckets->end(), first, first->begin());
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the beginning of the unordered_map.
+ ///\return A const iterator to the beginning of the unordered_map.
+ //*********************************************************************
+ const_iterator cbegin() const
+ {
+ return const_iterator(pbuckets->end(), first, first->begin());
+ }
+
+ //*********************************************************************
+ /// Returns an iterator to the beginning of the unordered_map bucket.
+ ///\return An iterator to the beginning of the unordered_map bucket.
+ //*********************************************************************
+ local_iterator begin(size_t i)
+ {
+ return (*pbuckets)[i].begin();
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the beginning of the unordered_map bucket.
+ ///\return A const iterator to the beginning of the unordered_map bucket.
+ //*********************************************************************
+ local_const_iterator begin(size_t i) const
+ {
+ return (*pbuckets)[i].cbegin();
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the beginning of the unordered_map bucket.
+ ///\return A const iterator to the beginning of the unordered_map bucket.
+ //*********************************************************************
+ local_const_iterator cbegin(size_t i) const
+ {
+ return (*pbuckets)[i].cbegin();
+ }
+
+ //*********************************************************************
+ /// Returns an iterator to the end of the unordered_map.
+ ///\return An iterator to the end of the unordered_map.
+ //*********************************************************************
+ iterator end()
+ {
+ return iterator(pbuckets->end(), last, last->end());
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the end of the unordered_map.
+ ///\return A const iterator to the end of the unordered_map.
+ //*********************************************************************
+ const_iterator end() const
+ {
+ return const_iterator(pbuckets->end(), last, last->end());
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the end of the unordered_map.
+ ///\return A const iterator to the end of the unordered_map.
+ //*********************************************************************
+ const_iterator cend() const
+ {
+ return const_iterator(pbuckets->end(), last, last->end());
+ }
+
+ //*********************************************************************
+ /// Returns an iterator to the end of the unordered_map bucket.
+ ///\return An iterator to the end of the unordered_map bucket.
+ //*********************************************************************
+ local_iterator end(size_t i)
+ {
+ return (*pbuckets)[i].end();
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the end of the unordered_map bucket.
+ ///\return A const iterator to the end of the unordered_map bucket.
+ //*********************************************************************
+ local_const_iterator end(size_t i) const
+ {
+ return (*pbuckets)[i].cend();
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the end of the unordered_map bucket.
+ ///\return A const iterator to the end of the unordered_map bucket.
+ //*********************************************************************
+ local_const_iterator cend(size_t i) const
+ {
+ return (*pbuckets)[i].cend();
+ }
+
+ //*********************************************************************
+ /// Returns the bucket index for the key.
+ ///\return The bucket index for the key.
+ //*********************************************************************
+ size_type bucket(key_value_parameter_t key) const
+ {
+ return key_hash_function(key) % pbuckets->size();
+ }
+
+ //*********************************************************************
+ /// Returns the size of the bucket key.
+ ///\return The bucket size of the bucket key.
+ //*********************************************************************
+ size_type bucket_size(key_value_parameter_t key) const
+ {
+ size_t index = bucket(key);
+
+ return std::distance((*pbuckets)[index].begin(), (*pbuckets)[index].end());
+ }
+
+ //*********************************************************************
+ /// Returns the maximum number of the buckets the container can hold.
+ ///\return The maximum number of the buckets the container can hold.
+ //*********************************************************************
+ size_type max_bucket_count() const
+ {
+ return max_size();
+ }
+
+ //*********************************************************************
+ /// Returns the number of the buckets the container holds.
+ ///\return The number of the buckets the container holds.
+ //*********************************************************************
+ size_type bucket_count() const
+ {
+ return max_size();
+ }
+
+ //*********************************************************************
+ /// Returns a reference to the value at index 'key'
+ ///\param key The key.
+ ///\return A reference to the value at index 'key'
+ //*********************************************************************
+ mapped_type& operator [](key_value_parameter_t key)
+ {
+ // Find the bucket.
+ bucket_list_iterator ibucket = pbuckets->begin() + bucket(key);
+
+ // Find the first node in the bucket.
+ local_iterator inode = ibucket->begin();
+
+ // Walk the list looking for the right one.
+ while (inode != ibucket->end())
+ {
+ // Equal keys?
+ if (key_equal_function(key, inode->key_value_pair.first))
+ {
+ // Found a match.
+ return inode->key_value_pair.second;
+ }
+ else
+ {
+ ++inode;
+ }
+ }
+
+ // Doesn't exist, so add a new one.
+ // Get a new node.
+ node_t& node = *pnodepool->allocate(node_t(value_type(key, T())));
+ ibucket->insert_after(ibucket->before_begin(), node);
+
+ return ibucket->begin()->key_value_pair.second;
+ }
+
+ //*********************************************************************
+ /// Returns a reference to the value at index 'key'
+ /// If asserts or exceptions are enabled, emits an etl::unordered_map_out_of_range if the key is not in the range.
+ ///\param key The key.
+ ///\return A reference to the value at index 'key'
+ //*********************************************************************
+ mapped_type& at(key_value_parameter_t key)
+ {
+ // Find the bucket.
+ bucket_list_iterator ibucket = pbuckets->begin() + bucket(key);
+
+ // Find the first node in the bucket.
+ local_iterator inode = ibucket->begin();
+
+ // Walk the list looking for the right one.
+ while (inode != ibucket->end())
+ {
+ // Equal keys?
+ if (key_equal_function(key, inode->key_value_pair.first))
+ {
+ // Found a match.
+ return inode->key_value_pair.second;
+ }
+ else
+ {
+ ++inode;
+ }
+ }
+
+ // Doesn't exist.
+ ETL_ASSERT(false, ETL_ERROR(unordered_map_out_of_range));
+
+ return begin()->second;
+ }
+
+ //*********************************************************************
+ /// Returns a const reference to the value at index 'key'
+ /// If asserts or exceptions are enabled, emits an etl::unordered_map_out_of_range if the key is not in the range.
+ ///\param key The key.
+ ///\return A const reference to the value at index 'key'
+ //*********************************************************************
+ const mapped_type& at(key_value_parameter_t key) const
+ {
+ // Find the bucket.
+ typename bucket_list_t::const_iterator ibucket = pbuckets->begin() + bucket(key);
+
+ // Find the first node in the bucket.
+ typename bucket_t::const_iterator inode = ibucket->begin();
+
+ // Walk the list looking for the right one.
+ while (inode != ibucket->end())
+ {
+ // Equal keys?
+ if (key_equal_function(key, inode->key_value_pair.first))
+ {
+ // Found a match.
+ return inode->key_value_pair.second;
+ }
+ else
+ {
+ ++inode;
+ }
+ }
+
+ // Doesn't exist.
+ ETL_ASSERT(false, ETL_ERROR(unordered_map_out_of_range));
+
+ return begin()->second;
+ }
+
+ //*********************************************************************
+ /// Assigns values to the unordered_map.
+ /// If asserts or exceptions are enabled, emits unordered_map_full if the unordered_map does not have enough free space.
+ /// If asserts or exceptions are enabled, emits unordered_map_iterator if the iterators are reversed.
+ ///\param first The iterator to the first element.
+ ///\param last The iterator to the last element + 1.
+ //*********************************************************************
+ template <typename TIterator>
+ void assign(TIterator first, TIterator last)
+ {
+#ifdef _DEBUG
+ difference_type count = std::distance(first, last);
+ ETL_ASSERT(count >= 0, ETL_ERROR(unordered_map_iterator));
+ ETL_ASSERT(size_t(count) <= max_size() , ETL_ERROR(unordered_map_full));
+#endif
+
+ clear();
+
+ while (first != last)
+ {
+ insert(*first++);
+ }
+ }
+
+ //*********************************************************************
+ /// Inserts a value to the unordered_map.
+ /// If asserts or exceptions are enabled, emits unordered_map_full if the unordered_map is already full.
+ ///\param value The value to insert.
+ //*********************************************************************
+ std::pair<iterator, bool> insert(const value_type& key_value_pair)
+ {
+ std::pair<iterator, bool> result(end(), false);
+
+ ETL_ASSERT(!full(), ETL_ERROR(unordered_map_full));
+
+ const key_type& key = key_value_pair.first;
+ const mapped_type& mapped = key_value_pair.second;
+
+ // Get the hash index.
+ size_t index = bucket(key);
+
+ // Get the bucket & bucket iterator.
+ bucket_list_iterator ibucket = pbuckets->begin() + index;
+ bucket_t& bucket = *ibucket;
+
+ // The first one in the bucket?
+ if (bucket.empty())
+ {
+ // Get a new node.
+ node_t& node = *pnodepool->allocate(node_t(key_value_pair));
+
+ // Just add the pointer to the bucket;
+ bucket.insert_after(bucket.before_begin(), node);
+
+ result.first = iterator(pbuckets->end(), ibucket, ibucket->begin());
+ result.second = true;
+
+ adjust_first_last_markers(ibucket);
+ }
+ else
+ {
+ // Step though the bucket looking for a place to insert.
+ local_iterator inode_previous = bucket.before_begin();
+ local_iterator inode = bucket.begin();
+
+ while (inode != bucket.end())
+ {
+ // Do we already have this key?
+ if (inode->key_value_pair.first == key)
+ {
+ break;
+ }
+
+ ++inode_previous;
+ ++inode;
+ }
+
+ // Not already there?
+ if (inode == bucket.end())
+ {
+ // Get a new node.
+ node_t& node = *pnodepool->allocate(node_t(key_value_pair));
+
+ // Add the node to the end of the bucket;
+ bucket.insert_after(inode_previous, node);
+ ++inode_previous;
+
+ result.first = iterator(pbuckets->end(), ibucket, inode_previous);
+ result.second = true;
+ }
+ }
+
+ return result;
+ }
+
+ //*********************************************************************
+ /// Inserts a value to the unordered_map.
+ /// If asserts or exceptions are enabled, emits unordered_map_full if the unordered_map is already full.
+ ///\param position The position to insert at.
+ ///\param value The value to insert.
+ //*********************************************************************
+ iterator insert(const_iterator position, const value_type& key_value_pair)
+ {
+ return insert(key_value_pair).first;
+ }
+
+ //*********************************************************************
+ /// Inserts a range of values to the unordered_map.
+ /// If asserts or exceptions are enabled, emits unordered_map_full if the unordered_map does not have enough free space.
+ ///\param position The position to insert at.
+ ///\param first The first element to add.
+ ///\param last The last + 1 element to add.
+ //*********************************************************************
+ template <class TIterator>
+ void insert(TIterator first, TIterator last)
+ {
+ while (first != last)
+ {
+ insert(*first++);
+ }
+ }
+
+ //*********************************************************************
+ /// Erases an element.
+ ///\param key The key to erase.
+ ///\return The number of elements erased. 0 or 1.
+ //*********************************************************************
+ size_t erase(key_value_parameter_t key)
+ {
+ size_t count = 0;
+ size_t bucket_id = bucket(key);
+
+ bucket_t& bucket = (*pbuckets)[bucket_id];
+
+ local_iterator iprevious = bucket.before_begin();
+ local_iterator icurrent = bucket.begin();
+
+ while ((icurrent != bucket.end()) && (icurrent->key_value_pair.first != key))
+ {
+ ++iprevious;
+ ++icurrent;
+ }
+
+ if (icurrent != bucket.end())
+ {
+ bucket.erase_after(iprevious);
+ count = 1;
+ }
+
+ return count;
+ }
+
+ //*********************************************************************
+ /// Erases an element.
+ ///\param ielement Iterator to the element.
+ //*********************************************************************
+ iterator erase(const_iterator ielement)
+ {
+ // Make a note of the next one.
+ iterator inext(pbuckets->end(), ielement.get_bucket_list_iterator(), ielement.get_local_iterator());
+ ++inext;
+
+ bucket_t& bucket = ielement.get_bucket();
+ local_iterator icurrent = ielement.get_local_iterator();
+ local_iterator iprevious = bucket.before_begin();
+
+ // Find the node we're interested in.
+ while (iprevious->etl_next != &*icurrent)
+ {
+ ++iprevious;
+ }
+
+ bucket.erase_after(iprevious);
+
+ return inext;
+ }
+
+ //*********************************************************************
+ /// Erases a range of elements.
+ /// The range includes all the elements between first and last, including the
+ /// element pointed by first, but not the one pointed to by last.
+ ///\param first Iterator to the first element.
+ ///\param last Iterator to the last element.
+ //*********************************************************************
+ iterator erase(const_iterator first, const_iterator last)
+ {
+ // Make a note of the last.
+ iterator result(pbuckets->end(), last.get_bucket_list_iterator(), last.get_local_iterator());
+
+ // Get the starting point.
+ bucket_list_iterator ibucket = first.get_bucket_list_iterator();
+ local_iterator ifirst = first.get_local_iterator();
+ local_iterator iprevious = ibucket->before_begin();
+ local_iterator iend;
+
+ // Find the first node we're interested in.
+ while (iprevious->etl_next != &*ifirst)
+ {
+ ++iprevious;
+ }
+
+ iend = iprevious;
+ iend++;
+
+ while (first != last)
+ {
+ // Find how far we can go in this bucket.
+ while ((first != last) && (iend != ibucket->end()))
+ {
+ ++first;
+ ++iend;
+ }
+
+ // Erase the range.
+ ibucket->erase_after(iprevious, iend);
+
+ // At the end of this bucket?
+ if (iend == ibucket->end())
+ {
+ // Move on to the next bucket.
+ ++ibucket;
+ iprevious = ibucket->before_begin();
+ iend = iprevious;
+ ++iend;
+ }
+ else
+ {
+ // Still in the same bucket.
+ iprevious = iend;
+ }
+ }
+
+ return result;
+ }
+
+ //*************************************************************************
+ /// Clears the unordered_map.
+ //*************************************************************************
+ void clear()
+ {
+ initialise();
+ }
+
+ //*********************************************************************
+ /// Counts an element.
+ ///\param key The key to search for.
+ ///\return 1 if the key exists, otherwise 0.
+ //*********************************************************************
+ size_t count(key_value_parameter_t key) const
+ {
+ return (find(key) == end()) ? 0 : 1;
+ }
+
+ //*********************************************************************
+ /// Finds an element.
+ ///\param key The key to search for.
+ ///\return An iterator to the element if the key exists, otherwise end().
+ //*********************************************************************
+ iterator find(key_value_parameter_t key)
+ {
+ size_t index = bucket(key);
+
+ bucket_list_iterator ibucket = pbuckets->begin() + index;
+ bucket_t& bucket = *ibucket;
+
+ // Is the bucket not empty?
+ if (!bucket.empty())
+ {
+ // Step though the list until we find the end or an equivalent key.
+ local_iterator inode = bucket.begin();
+ local_iterator iend = bucket.end();
+
+ while (inode != iend)
+ {
+ // Do we have this one?
+ if (key_equal_function(key, inode->key_value_pair.first))
+ {
+ return iterator(pbuckets->end(), ibucket, inode);
+ }
+
+ ++inode;
+ }
+ }
+
+ return end();
+ }
+
+ //*********************************************************************
+ /// Finds an element.
+ ///\param key The key to search for.
+ ///\return An iterator to the element if the key exists, otherwise end().
+ //*********************************************************************
+ const_iterator find(key_value_parameter_t key) const
+ {
+ size_t index = bucket(key);
+
+ bucket_list_iterator ibucket = pbuckets->begin() + index;
+ bucket_t& bucket = *ibucket;
+
+ // Is the bucket not empty?
+ if (!bucket.empty())
+ {
+ // Step though the list until we find the end or an equivalent key.
+ local_iterator inode = bucket.begin();
+ local_iterator iend = bucket.end();
+
+ while (inode != iend)
+ {
+ // Do we have this one?
+ if (key_equal_function(key, inode->key_value_pair.first))
+ {
+ return iterator(pbuckets->end(), ibucket, inode);
+ }
+
+ ++inode;
+ }
+ }
+
+ return end();
+ }
+
+ //*********************************************************************
+ /// Returns a range containing all elements with key key in the container.
+ /// The range is defined by two iterators, the first pointing to the first
+ /// element of the wanted range and the second pointing past the last
+ /// element of the range.
+ ///\param key The key to search for.
+ ///\return An iterator pair to the range of elements if the key exists, otherwise end().
+ //*********************************************************************
+ std::pair<iterator, iterator> equal_range(const key_value_parameter_t& key)
+ {
+ iterator first = find(key);
+ iterator last = first;
+
+ if (last != end())
+ {
+ ++last;
+ }
+
+ return std::pair<iterator, iterator>(first, last);
+ }
+
+ //*********************************************************************
+ /// Returns a range containing all elements with key key in the container.
+ /// The range is defined by two iterators, the first pointing to the first
+ /// element of the wanted range and the second pointing past the last
+ /// element of the range.
+ ///\param key The key to search for.
+ ///\return A const iterator pair to the range of elements if the key exists, otherwise end().
+ //*********************************************************************
+ std::pair<const_iterator, const_iterator> equal_range(const key_value_parameter_t& key) const
+ {
+ const_iterator first = find(key);
+ const_iterator last = first;
+
+ if (last != end())
+ {
+ ++last;
+ }
+
+ return std::pair<const_iterator, const_iterator>(first, last);
+ }
+
+ //*************************************************************************
+ /// Gets the size of the unordered_map.
+ //*************************************************************************
+ size_type size() const
+ {
+ return pnodepool->size();
+ }
+
+ //*************************************************************************
+ /// Gets the maximum possible size of the unordered_map.
+ //*************************************************************************
+ size_type max_size() const
+ {
+ return pnodepool->max_size();
+ }
+
+ //*************************************************************************
+ /// Checks to see if the unordered_map is empty.
+ //*************************************************************************
+ bool empty() const
+ {
+ return pnodepool->empty();
+ }
+
+ //*************************************************************************
+ /// Checks to see if the unordered_map is full.
+ //*************************************************************************
+ bool full() const
+ {
+ return pnodepool->full();
+ }
+
+ //*************************************************************************
+ /// Returns the remaining capacity.
+ ///\return The remaining capacity.
+ //*************************************************************************
+ size_t available() const
+ {
+ return pnodepool->available();
+ }
+
+ //*************************************************************************
+ /// Returns the load factor = size / bucket_count.
+ ///\return The load factor = size / bucket_count.
+ //*************************************************************************
+ float load_factor() const
+ {
+ return static_cast<float>(size()) / static_cast<float>(bucket_count());
+ }
+
+ //*************************************************************************
+ /// Returns the function that hashes the keys.
+ ///\return The function that hashes the keys..
+ //*************************************************************************
+ hasher hash_function() const
+ {
+ return key_hash_function;
+ }
+
+ //*************************************************************************
+ /// Returns the function that compares the keys.
+ ///\return The function that compares the keys..
+ //*************************************************************************
+ key_equal key_eq() const
+ {
+ return key_equal_function;
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ iunordered_map& operator = (const iunordered_map& rhs)
+ {
+ // Skip if doing self assignment
+ if (this != &rhs)
+ {
+ assign(rhs.cbegin(), rhs.cend());
+ }
+
+ return *this;
+ }
+
+ protected:
+
+ //*********************************************************************
+ /// Constructor.
+ //*********************************************************************
+ iunordered_map(pool_t& node_pool, bucket_list_t& buckets)
+ : pnodepool(&node_pool),
+ pbuckets(&buckets)
+ {
+ }
+
+ //*********************************************************************
+ /// Initialise the unordered_map.
+ //*********************************************************************
+ void initialise()
+ {
+ pbuckets->resize(pnodepool->max_size());
+
+ if (!empty())
+ {
+ pnodepool->release_all();
+
+ for (size_t i = 0; i < pbuckets->size(); ++i)
+ {
+ (*pbuckets)[i].clear();
+ }
+ }
+
+ first = pbuckets->begin();
+ last = first;
+ }
+
+ private:
+
+ //*********************************************************************
+ /// Adjust the first and last markers according to the new entry.
+ //*********************************************************************
+ void adjust_first_last_markers(bucket_list_iterator ibucket)
+ {
+ if (ibucket < first)
+ {
+ first = ibucket;
+ }
+ else if (ibucket > last)
+ {
+ last = ibucket;
+ }
+ }
+
+ // Disable copy construction.
+ iunordered_map(const iunordered_map&);
+
+ /// The pool of data nodes used in the list.
+ pool_t* pnodepool;
+
+ /// The bucket list.
+ bucket_list_t* pbuckets;
+
+ /// The first and last iterators to buckets with values.
+ bucket_list_iterator first;
+ bucket_list_iterator last;
+
+ /// The function that creates the hashes.
+ hasher key_hash_function;
+
+ /// The function that compares the keys for equality.
+ key_equal key_equal_function;
+ };
+
+ //***************************************************************************
+ /// Equal operator.
+ ///\param lhs Reference to the first unordered_map.
+ ///\param rhs Reference to the second unordered_map.
+ ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
+ ///\ingroup unordered_map
+ //***************************************************************************
+ template <typename TKey, typename TMapped, typename TKeyCompare>
+ bool operator ==(const etl::iunordered_map<TKey, TMapped, TKeyCompare>& lhs, const etl::iunordered_map<TKey, TMapped, TKeyCompare>& rhs)
+ {
+ return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin());
+ }
+
+ //***************************************************************************
+ /// Not equal operator.
+ ///\param lhs Reference to the first unordered_map.
+ ///\param rhs Reference to the second unordered_map.
+ ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
+ ///\ingroup unordered_map
+ //***************************************************************************
+ template <typename TKey, typename TMapped, typename TKeyCompare>
+ bool operator !=(const etl::iunordered_map<TKey, TMapped, TKeyCompare>& lhs, const etl::iunordered_map<TKey, TMapped, TKeyCompare>& rhs)
+ {
+ return !(lhs == rhs);
+ }
+}
+
+#undef ETL_FILE
+#endif
diff --git a/lib/etl/iunordered_multimap.h b/lib/etl/iunordered_multimap.h
new file mode 100644
index 0000000..2d2ba70
--- /dev/null
+++ b/lib/etl/iunordered_multimap.h
@@ -0,0 +1,1191 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_IUNORDERED_MULTIMAP__
+#define __ETL_IUNORDERED_MULTIMAP__
+
+#include <iterator>
+#include <algorithm>
+#include <functional>
+#include <utility>
+#include <stddef.h>
+
+#include "type_traits.h"
+#include "parameter_type.h"
+#include "hash.h"
+#include "nullptr.h"
+#include "ipool.h"
+#include "ivector.h"
+#include "error_handler.h"
+#include "intrusive_forward_list.h"
+#include "exception.h"
+#include "error_handler.h"
+
+#undef ETL_FILE
+#define ETL_FILE "25"
+
+namespace etl
+{
+ //***************************************************************************
+ /// Exception for the unordered_multimap.
+ ///\ingroup unordered_multimap
+ //***************************************************************************
+ class unordered_multimap_exception : public exception
+ {
+ public:
+
+ unordered_multimap_exception(string_type what, string_type file_name, numeric_type line_number)
+ : exception(what, file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// Full exception for the unordered_multimap.
+ ///\ingroup unordered_multimap
+ //***************************************************************************
+ class unordered_multimap_full : public unordered_multimap_exception
+ {
+ public:
+
+ unordered_multimap_full(string_type file_name, numeric_type line_number)
+ : unordered_multimap_exception(ETL_ERROR_TEXT("unordered_multimap:full", ETL_FILE"A"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// Out of range exception for the unordered_multimap.
+ ///\ingroup unordered_multimap
+ //***************************************************************************
+ class unordered_multimap_out_of_range : public unordered_multimap_exception
+ {
+ public:
+
+ unordered_multimap_out_of_range(string_type file_name, numeric_type line_number)
+ : unordered_multimap_exception(ETL_ERROR_TEXT("unordered_multimap:range", ETL_FILE"B"), file_name, line_number)
+ {}
+ };
+
+ //***************************************************************************
+ /// Iterator exception for the unordered_multimap.
+ ///\ingroup unordered_multimap
+ //***************************************************************************
+ class unordered_multimap_iterator : public unordered_multimap_exception
+ {
+ public:
+
+ unordered_multimap_iterator(string_type file_name, numeric_type line_number)
+ : unordered_multimap_exception(ETL_ERROR_TEXT("unordered_multimap:iterator", ETL_FILE"C"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// The base class for specifically sized unordered_multimap.
+ /// Can be used as a reference type for all unordered_multimap containing a specific type.
+ ///\ingroup unordered_multimap
+ //***************************************************************************
+ template <typename TKey, typename T, typename THash = etl::hash<TKey>, typename TKeyEqual = std::equal_to<TKey> >
+ class iunordered_multimap
+ {
+ public:
+
+ typedef std::pair<const TKey, T> value_type;
+
+ typedef TKey key_type;
+ typedef T mapped_type;
+ typedef THash hasher;
+ typedef TKeyEqual key_equal;
+ typedef value_type& reference;
+ typedef const value_type& const_reference;
+ typedef value_type* pointer;
+ typedef const value_type* const_pointer;
+ typedef size_t size_type;
+
+
+ typedef typename parameter_type<TKey>::type key_value_parameter_t;
+
+ typedef etl::forward_link<0> link_t; // Default link.
+
+ // The nodes that store the elements.
+ struct node_t : public link_t
+ {
+ node_t(const value_type& key_value_pair)
+ : key_value_pair(key_value_pair)
+ {
+ }
+
+ value_type key_value_pair;
+ };
+
+ private:
+
+ typedef etl::intrusive_forward_list<node_t, link_t> bucket_t;
+ typedef etl::ipool<node_t> pool_t;
+ typedef etl::ivector<bucket_t> bucket_list_t;
+
+ typedef typename bucket_list_t::iterator bucket_list_iterator;
+
+ public:
+
+ // Local iterators iterate over one bucket.
+ typedef typename bucket_t::iterator local_iterator;
+ typedef typename bucket_t::const_iterator local_const_iterator;
+
+ //*********************************************************************
+ class iterator : public std::iterator<std::forward_iterator_tag, T>
+ {
+ public:
+
+ typedef typename iunordered_multimap::value_type value_type;
+ typedef typename iunordered_multimap::key_type key_type;
+ typedef typename iunordered_multimap::mapped_type mapped_type;
+ typedef typename iunordered_multimap::hasher hasher;
+ typedef typename iunordered_multimap::key_equal key_equal;
+ typedef typename iunordered_multimap::reference reference;
+ typedef typename iunordered_multimap::const_reference const_reference;
+ typedef typename iunordered_multimap::pointer pointer;
+ typedef typename iunordered_multimap::const_pointer const_pointer;
+ typedef typename iunordered_multimap::size_type size_type;
+
+ friend class iunordered_multimap;
+
+ //*********************************
+ iterator()
+ {
+ }
+
+ //*********************************
+ iterator(const iterator& other)
+ : ibuckets_end(other.ibuckets_end),
+ ibucket(other.ibucket),
+ inode(other.inode)
+ {
+ }
+
+ //*********************************
+ iterator& operator ++()
+ {
+ ++inode;
+
+ // The end of this node list?
+ if (inode == ibucket->end())
+ {
+ // Search for the next non-empty bucket.
+ ++ibucket;
+ while ((ibucket != ibuckets_end) && (ibucket->empty()))
+ {
+ ++ibucket;
+ }
+
+ // If not past the end, get the first node in the bucket.
+ if (ibucket != ibuckets_end)
+ {
+ inode = ibucket->begin();
+ }
+ }
+
+ return *this;
+ }
+
+ //*********************************
+ iterator operator ++(int)
+ {
+ iterator temp(*this);
+ operator++();
+ return temp;
+ }
+
+ //*********************************
+ iterator operator =(const iterator& other)
+ {
+ ibuckets_end = other.ibuckets_end;
+ ibucket = other.ibucket;
+ inode = other.inode;
+ return *this;
+ }
+
+ //*********************************
+ std::pair<const TKey, T> operator *()
+ {
+ return inode->key_value_pair;
+ }
+
+ //*********************************
+ const_reference operator *() const
+ {
+ return inode->key_value_pair;
+ }
+
+ //*********************************
+ pointer operator &()
+ {
+ return &(inode->key_value_pair);
+ }
+
+ //*********************************
+ const_pointer operator &() const
+ {
+ return &(inode->key_value_pair);
+ }
+
+ //*********************************
+ pointer operator ->()
+ {
+ return &(inode->key_value_pair);
+ }
+
+ //*********************************
+ const_pointer operator ->() const
+ {
+ return &(inode->key_value_pair);
+ }
+
+ //*********************************
+ friend bool operator == (const iterator& lhs, const iterator& rhs)
+ {
+ return lhs.compare(rhs);
+ }
+
+ //*********************************
+ friend bool operator != (const iterator& lhs, const iterator& rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+ private:
+
+ //*********************************
+ iterator(bucket_list_iterator ibuckets_end, bucket_list_iterator ibucket, local_iterator inode)
+ : ibuckets_end(ibuckets_end),
+ ibucket(ibucket),
+ inode(inode)
+ {
+ }
+
+ //*********************************
+ bool compare(const iterator& rhs) const
+ {
+ return rhs.inode == inode;
+ }
+
+ //*********************************
+ bucket_t& get_bucket()
+ {
+ return *ibucket;
+ }
+
+ //*********************************
+ bucket_list_iterator& get_bucket_list_iterator()
+ {
+ return ibucket;
+ }
+
+ //*********************************
+ local_iterator get_local_iterator()
+ {
+ return inode;
+ }
+
+ bucket_list_iterator ibuckets_end;
+ bucket_list_iterator ibucket;
+ local_iterator inode;
+ };
+
+ //*********************************************************************
+ class const_iterator : public std::iterator<std::forward_iterator_tag, const T>
+ {
+ public:
+
+ typedef typename iunordered_multimap::value_type value_type;
+ typedef typename iunordered_multimap::key_type key_type;
+ typedef typename iunordered_multimap::mapped_type mapped_type;
+ typedef typename iunordered_multimap::hasher hasher;
+ typedef typename iunordered_multimap::key_equal key_equal;
+ typedef typename iunordered_multimap::reference reference;
+ typedef typename iunordered_multimap::const_reference const_reference;
+ typedef typename iunordered_multimap::pointer pointer;
+ typedef typename iunordered_multimap::const_pointer const_pointer;
+ typedef typename iunordered_multimap::size_type size_type;
+
+ friend class iunordered_multimap;
+ friend class iterator;
+
+ //*********************************
+ const_iterator()
+ {
+ }
+
+ //*********************************
+ const_iterator(const typename iunordered_multimap::iterator& other)
+ : ibuckets_end(other.ibuckets_end),
+ ibucket(other.ibucket),
+ inode(other.inode)
+ {
+ }
+
+ //*********************************
+ const_iterator(const const_iterator& other)
+ : ibuckets_end(other.ibuckets_end),
+ ibucket(other.ibucket),
+ inode(other.inode)
+ {
+ }
+
+ //*********************************
+ const_iterator& operator ++()
+ {
+ ++inode;
+
+ // The end of this node list?
+ if (inode == ibucket->end())
+ {
+ // Search for the next non-empty bucket.
+
+ ++ibucket;
+ while ((ibucket != ibuckets_end) && (ibucket->empty()))
+ {
+ ++ibucket;
+ }
+
+ // If not past the end, get the first node in the bucket.
+ if (ibucket != ibuckets_end)
+ {
+ inode = ibucket->begin();
+ }
+ }
+
+ return *this;
+ }
+
+ //*********************************
+ const_iterator operator ++(int)
+ {
+ const_iterator temp(*this);
+ operator++();
+ return temp;
+ }
+
+ //*********************************
+ const_iterator operator =(const const_iterator& other)
+ {
+ ibuckets_end = other.ibuckets_end;
+ ibucket = other.ibucket;
+ inode = other.inode;
+ return *this;
+ }
+
+ //*********************************
+ const_reference operator *() const
+ {
+ return inode->key_value_pair;
+ }
+
+ //*********************************
+ const_pointer operator &() const
+ {
+ return &(inode->key_value_pair);
+ }
+
+ //*********************************
+ const_pointer operator ->() const
+ {
+ return &(inode->key_value_pair);
+ }
+
+ //*********************************
+ friend bool operator == (const const_iterator& lhs, const const_iterator& rhs)
+ {
+ return lhs.compare(rhs);
+ }
+
+ //*********************************
+ friend bool operator != (const const_iterator& lhs, const const_iterator& rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+ private:
+
+ //*********************************
+ const_iterator(bucket_list_iterator ibuckets_end, bucket_list_iterator ibucket, local_iterator inode)
+ : ibuckets_end(ibuckets_end),
+ ibucket(ibucket),
+ inode(inode)
+ {
+ }
+
+ //*********************************
+ bool compare(const const_iterator& rhs) const
+ {
+ return rhs.inode == inode;
+ }
+
+ //*********************************
+ bucket_t& get_bucket()
+ {
+ return *ibucket;
+ }
+
+ //*********************************
+ bucket_list_iterator& get_bucket_list_iterator()
+ {
+ return ibucket;
+ }
+
+ //*********************************
+ local_iterator get_local_iterator()
+ {
+ return inode;
+ }
+
+ bucket_list_iterator ibuckets_end;
+ bucket_list_iterator ibucket;
+ local_iterator inode;
+ };
+
+ typedef typename std::iterator_traits<iterator>::difference_type difference_type;
+
+ //*********************************************************************
+ /// Returns an iterator to the beginning of the unordered_multimap.
+ ///\return An iterator to the beginning of the unordered_multimap.
+ //*********************************************************************
+ iterator begin()
+ {
+ return iterator(pbuckets->end(), first, first->begin());
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the beginning of the unordered_multimap.
+ ///\return A const iterator to the beginning of the unordered_multimap.
+ //*********************************************************************
+ const_iterator begin() const
+ {
+ return const_iterator(pbuckets->end(), first, first->begin());
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the beginning of the unordered_multimap.
+ ///\return A const iterator to the beginning of the unordered_multimap.
+ //*********************************************************************
+ const_iterator cbegin() const
+ {
+ return const_iterator(pbuckets->end(), first, first->begin());
+ }
+
+ //*********************************************************************
+ /// Returns an iterator to the beginning of the unordered_multimap bucket.
+ ///\return An iterator to the beginning of the unordered_multimap bucket.
+ //*********************************************************************
+ local_iterator begin(size_t i)
+ {
+ return (*pbuckets)[i].begin();
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the beginning of the unordered_multimap bucket.
+ ///\return A const iterator to the beginning of the unordered_multimap bucket.
+ //*********************************************************************
+ local_const_iterator begin(size_t i) const
+ {
+ return (*pbuckets)[i].cbegin();
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the beginning of the unordered_multimap bucket.
+ ///\return A const iterator to the beginning of the unordered_multimap bucket.
+ //*********************************************************************
+ local_const_iterator cbegin(size_t i) const
+ {
+ return (*pbuckets)[i].cbegin();
+ }
+
+ //*********************************************************************
+ /// Returns an iterator to the end of the unordered_multimap.
+ ///\return An iterator to the end of the unordered_multimap.
+ //*********************************************************************
+ iterator end()
+ {
+ return iterator(pbuckets->end(), last, last->end());
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the end of the unordered_multimap.
+ ///\return A const iterator to the end of the unordered_multimap.
+ //*********************************************************************
+ const_iterator end() const
+ {
+ return const_iterator(pbuckets->end(), last, last->end());
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the end of the unordered_multimap.
+ ///\return A const iterator to the end of the unordered_multimap.
+ //*********************************************************************
+ const_iterator cend() const
+ {
+ return const_iterator(pbuckets->end(), last, last->end());
+ }
+
+ //*********************************************************************
+ /// Returns an iterator to the end of the unordered_multimap bucket.
+ ///\return An iterator to the end of the unordered_multimap bucket.
+ //*********************************************************************
+ local_iterator end(size_t i)
+ {
+ return (*pbuckets)[i].end();
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the end of the unordered_multimap bucket.
+ ///\return A const iterator to the end of the unordered_multimap bucket.
+ //*********************************************************************
+ local_const_iterator end(size_t i) const
+ {
+ return (*pbuckets)[i].cend();
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the end of the unordered_multimap bucket.
+ ///\return A const iterator to the end of the unordered_multimap bucket.
+ //*********************************************************************
+ local_const_iterator cend(size_t i) const
+ {
+ return (*pbuckets)[i].cend();
+ }
+
+ //*********************************************************************
+ /// Returns the bucket index for the key.
+ ///\return The bucket index for the key.
+ //*********************************************************************
+ size_type bucket(key_value_parameter_t key) const
+ {
+ return key_hash_function(key) % pbuckets->size();
+ }
+
+ //*********************************************************************
+ /// Returns the size of the bucket key.
+ ///\return The bucket size of the bucket key.
+ //*********************************************************************
+ size_type bucket_size(key_value_parameter_t key) const
+ {
+ size_t index = bucket(key);
+
+ return std::distance((*pbuckets)[index].begin(), (*pbuckets)[index].end());
+ }
+
+ //*********************************************************************
+ /// Returns the maximum number of the buckets the container can hold.
+ ///\return The maximum number of the buckets the container can hold.
+ //*********************************************************************
+ size_type max_bucket_count() const
+ {
+ return max_size();
+ }
+
+ //*********************************************************************
+ /// Returns the number of the buckets the container holds.
+ ///\return The number of the buckets the container holds.
+ //*********************************************************************
+ size_type bucket_count() const
+ {
+ return max_size();
+ }
+
+ //*********************************************************************
+ /// Assigns values to the unordered_multimap.
+ /// If asserts or exceptions are enabled, emits unordered_multimap_full if the unordered_multimap does not have enough free space.
+ /// If asserts or exceptions are enabled, emits unordered_multimap_iterator if the iterators are reversed.
+ ///\param first The iterator to the first element.
+ ///\param last The iterator to the last element + 1.
+ //*********************************************************************
+ template <typename TIterator>
+ void assign(TIterator first, TIterator last)
+ {
+#ifdef _DEBUG
+ difference_type count = std::distance(first, last);
+ ETL_ASSERT(count >= 0, ETL_ERROR(unordered_multimap_iterator));
+ ETL_ASSERT(size_t(count) <= max_size() , ETL_ERROR(unordered_multimap_full));
+#endif
+
+ clear();
+
+ while (first != last)
+ {
+ insert(*first++);
+ }
+ }
+
+ //*********************************************************************
+ /// Inserts a value to the unordered_multimap.
+ /// If asserts or exceptions are enabled, emits unordered_multimap_full if the unordered_multimap is already full.
+ ///\param value The value to insert.
+ //*********************************************************************
+ std::pair<iterator, bool> insert(const value_type& key_value_pair)
+ {
+ std::pair<iterator, bool> result(end(), false);
+
+ ETL_ASSERT(!full(), ETL_ERROR(unordered_multimap_full));
+
+ const key_type& key = key_value_pair.first;
+ const mapped_type& mapped = key_value_pair.second;
+
+ // Get the hash index.
+ size_t index = bucket(key);
+
+ // Get the bucket & bucket iterator.
+ bucket_list_iterator ibucket = pbuckets->begin() + index;
+ bucket_t& bucket = *ibucket;
+
+ // The first one in the bucket?
+ if (bucket.empty())
+ {
+ // Get a new node.
+ node_t& node = *pnodepool->allocate(node_t(key_value_pair));
+
+ // Just add the pointer to the bucket;
+ bucket.insert_after(bucket.before_begin(), node);
+
+ result.first = iterator(pbuckets->end(), ibucket, ibucket->begin());
+ result.second = true;
+
+ adjust_first_last_markers(ibucket);
+ }
+ else
+ {
+ // Step though the bucket looking for a place to insert.
+ local_iterator inode_previous = bucket.before_begin();
+ local_iterator inode = bucket.begin();
+
+ while (inode != bucket.end())
+ {
+ // Do we already have this key?
+ if (inode->key_value_pair.first == key)
+ {
+ break;
+ }
+
+ ++inode_previous;
+ ++inode;
+ }
+
+ // Get a new node.
+ node_t& node = *pnodepool->allocate(node_t(key_value_pair));
+
+ // Add the node to the end of the bucket;
+ bucket.insert_after(inode_previous, node);
+ ++inode_previous;
+
+ result.first = iterator(pbuckets->end(), ibucket, inode_previous);
+ result.second = true;
+ }
+
+ return result;
+ }
+
+ //*********************************************************************
+ /// Inserts a value to the unordered_multimap.
+ /// If asserts or exceptions are enabled, emits unordered_multimap_full if the unordered_multimap is already full.
+ ///\param position The position to insert at.
+ ///\param value The value to insert.
+ //*********************************************************************
+ iterator insert(const_iterator position, const value_type& key_value_pair)
+ {
+ return insert(key_value_pair).first;
+ }
+
+ //*********************************************************************
+ /// Inserts a range of values to the unordered_multimap.
+ /// If asserts or exceptions are enabled, emits unordered_multimap_full if the unordered_multimap does not have enough free space.
+ ///\param position The position to insert at.
+ ///\param first The first element to add.
+ ///\param last The last + 1 element to add.
+ //*********************************************************************
+ template <class TIterator>
+ void insert(TIterator first, TIterator last)
+ {
+ while (first != last)
+ {
+ insert(*first++);
+ }
+ }
+
+ //*********************************************************************
+ /// Erases an element.
+ ///\param key The key to erase.
+ ///\return The number of elements erased.
+ //*********************************************************************
+ size_t erase(key_value_parameter_t key)
+ {
+ size_t count = 0;
+ size_t bucket_id = bucket(key);
+
+ bucket_t& bucket = (*pbuckets)[bucket_id];
+
+ local_iterator iprevious = bucket.before_begin();
+ local_iterator icurrent = bucket.begin();
+
+ while (icurrent != bucket.end())
+ {
+ if (icurrent->key_value_pair.first == key)
+ {
+ bucket.erase_after(iprevious);
+ ++count;
+ icurrent = iprevious;
+ }
+ else
+ {
+ ++iprevious;
+ }
+
+ ++icurrent;
+ }
+
+ return count;
+ }
+
+ //*********************************************************************
+ /// Erases an element.
+ ///\param ielement Iterator to the element.
+ //*********************************************************************
+ iterator erase(const_iterator ielement)
+ {
+ // Make a note of the next one.
+ iterator inext(pbuckets->end(), ielement.get_bucket_list_iterator(), ielement.get_local_iterator());
+ ++inext;
+
+ bucket_t& bucket = ielement.get_bucket();
+ local_iterator icurrent = ielement.get_local_iterator();
+ local_iterator iprevious = bucket.before_begin();
+
+ // Find the node we're interested in.
+ while (iprevious->etl_next != &*icurrent)
+ {
+ ++iprevious;
+ }
+
+ bucket.erase_after(iprevious);
+
+ return inext;
+ }
+
+ //*********************************************************************
+ /// Erases a range of elements.
+ /// The range includes all the elements between first and last, including the
+ /// element pointed by first, but not the one pointed to by last.
+ ///\param first Iterator to the first element.
+ ///\param last Iterator to the last element.
+ //*********************************************************************
+ iterator erase(const_iterator first, const_iterator last)
+ {
+ // Make a note of the last.
+ iterator result(pbuckets->end(), last.get_bucket_list_iterator(), last.get_local_iterator());
+
+ // Get the starting point.
+ bucket_list_iterator ibucket = first.get_bucket_list_iterator();
+ local_iterator ifirst = first.get_local_iterator();
+ local_iterator iprevious = ibucket->before_begin();
+ local_iterator iend;
+
+ // Find the first node we're interested in.
+ while (iprevious->etl_next != &*ifirst)
+ {
+ ++iprevious;
+ }
+
+ iend = iprevious;
+ iend++;
+
+ while (first != last)
+ {
+ // Find how far we can go in this bucket.
+ while ((first != last) && (iend != ibucket->end()))
+ {
+ ++first;
+ ++iend;
+ }
+
+ // Erase the range.
+ ibucket->erase_after(iprevious, iend);
+
+ // At the end of this bucket?
+ if (iend == ibucket->end())
+ {
+ // Move on to the next bucket.
+ ++ibucket;
+ iprevious = ibucket->before_begin();
+ iend = iprevious;
+ ++iend;
+ }
+ else
+ {
+ // Still in the same bucket.
+ iprevious = iend;
+ }
+ }
+
+ return result;
+ }
+
+ //*************************************************************************
+ /// Clears the unordered_multimap.
+ //*************************************************************************
+ void clear()
+ {
+ initialise();
+ }
+
+ //*********************************************************************
+ /// Counts an element.
+ ///\param key The key to search for.
+ ///\return 1 if the key exists, otherwise 0.
+ //*********************************************************************
+ size_t count(key_value_parameter_t key) const
+ {
+ size_t n = 0;
+ const_iterator first = find(key);
+ const_iterator last = first;
+
+ if (last != end())
+ {
+ ++last;
+ ++n;
+
+ while ((last != end()) && (key == last->first))
+ {
+ ++last;
+ ++n;
+ }
+ }
+
+ return n;
+ }
+
+ //*********************************************************************
+ /// Finds an element.
+ ///\param key The key to search for.
+ ///\return An iterator to the element if the key exists, otherwise end().
+ //*********************************************************************
+ iterator find(key_value_parameter_t key)
+ {
+ size_t index = bucket(key);
+
+ bucket_list_iterator ibucket = pbuckets->begin() + index;
+ bucket_t& bucket = *ibucket;
+
+ // Is the bucket not empty?
+ if (!bucket.empty())
+ {
+ // Step though the list until we find the end or an equivalent key.
+ local_iterator inode = bucket.begin();
+ local_iterator iend = bucket.end();
+
+ while (inode != iend)
+ {
+ // Do we have this one?
+ if (key_equal_function(key, inode->key_value_pair.first))
+ {
+ return iterator(pbuckets->end(), ibucket, inode);
+ }
+
+ ++inode;
+ }
+ }
+
+ return end();
+ }
+
+ //*********************************************************************
+ /// Finds an element.
+ ///\param key The key to search for.
+ ///\return An iterator to the element if the key exists, otherwise end().
+ //*********************************************************************
+ const_iterator find(key_value_parameter_t key) const
+ {
+ size_t index = bucket(key);
+
+ bucket_list_iterator ibucket = pbuckets->begin() + index;
+ bucket_t& bucket = *ibucket;
+
+ // Is the bucket not empty?
+ if (!bucket.empty())
+ {
+ // Step though the list until we find the end or an equivalent key.
+ local_iterator inode = bucket.begin();
+ local_iterator iend = bucket.end();
+
+ while (inode != iend)
+ {
+ // Do we have this one?
+ if (key_equal_function(key, inode->key_value_pair.first))
+ {
+ return const_iterator(pbuckets->end(), ibucket, inode);
+ }
+
+ ++inode;
+ }
+ }
+
+ return end();
+ }
+
+ //*********************************************************************
+ /// Returns a range containing all elements with key key in the container.
+ /// The range is defined by two iterators, the first pointing to the first
+ /// element of the wanted range and the second pointing past the last
+ /// element of the range.
+ ///\param key The key to search for.
+ ///\return An iterator pair to the range of elements if the key exists, otherwise end().
+ //*********************************************************************
+ std::pair<iterator, iterator> equal_range(const key_value_parameter_t& key)
+ {
+ iterator first = find(key);
+ iterator last = first;
+
+ if (last != end())
+ {
+ ++last;
+
+ while ((last != end()) && (key == last->first))
+ {
+ ++last;
+ }
+ }
+
+ return std::pair<iterator, iterator>(first, last);
+ }
+
+ //*********************************************************************
+ /// Returns a range containing all elements with key key in the container.
+ /// The range is defined by two iterators, the first pointing to the first
+ /// element of the wanted range and the second pointing past the last
+ /// element of the range.
+ ///\param key The key to search for.
+ ///\return A const iterator pair to the range of elements if the key exists, otherwise end().
+ //*********************************************************************
+ std::pair<const_iterator, const_iterator> equal_range(const key_value_parameter_t& key) const
+ {
+ const_iterator first = find(key);
+ const_iterator last = first;
+
+ if (last != end())
+ {
+ ++last;
+
+ while ((last != end()) && (key == last->first))
+ {
+ ++last;
+ }
+ }
+
+ return std::pair<const_iterator, const_iterator>(first, last);
+ }
+
+ //*************************************************************************
+ /// Gets the size of the unordered_multimap.
+ //*************************************************************************
+ size_type size() const
+ {
+ return pnodepool->size();
+ }
+
+ //*************************************************************************
+ /// Gets the maximum possible size of the unordered_multimap.
+ //*************************************************************************
+ size_type max_size() const
+ {
+ return pnodepool->max_size();
+ }
+
+ //*************************************************************************
+ /// Checks to see if the unordered_multimap is empty.
+ //*************************************************************************
+ bool empty() const
+ {
+ return pnodepool->empty();
+ }
+
+ //*************************************************************************
+ /// Checks to see if the unordered_multimap is full.
+ //*************************************************************************
+ bool full() const
+ {
+ return pnodepool->full();
+ }
+
+ //*************************************************************************
+ /// Returns the remaining capacity.
+ ///\return The remaining capacity.
+ //*************************************************************************
+ size_t available() const
+ {
+ return pnodepool->available();
+ }
+
+ //*************************************************************************
+ /// Returns the load factor = size / bucket_count.
+ ///\return The load factor = size / bucket_count.
+ //*************************************************************************
+ float load_factor() const
+ {
+ return static_cast<float>(size()) / static_cast<float>(bucket_count());
+ }
+
+ //*************************************************************************
+ /// Returns the function that hashes the keys.
+ ///\return The function that hashes the keys..
+ //*************************************************************************
+ hasher hash_function() const
+ {
+ return key_hash_function;
+ }
+
+ //*************************************************************************
+ /// Returns the function that compares the keys.
+ ///\return The function that compares the keys..
+ //*************************************************************************
+ key_equal key_eq() const
+ {
+ return key_equal_function;
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ iunordered_multimap& operator = (const iunordered_multimap& rhs)
+ {
+ // Skip if doing self assignment
+ if (this != &rhs)
+ {
+ assign(rhs.cbegin(), rhs.cend());
+ }
+
+ return *this;
+ }
+
+ protected:
+
+ //*********************************************************************
+ /// Constructor.
+ //*********************************************************************
+ iunordered_multimap(pool_t& node_pool, bucket_list_t& buckets)
+ : pnodepool(&node_pool),
+ pbuckets(&buckets)
+ {
+ }
+
+ //*********************************************************************
+ /// Initialise the unordered_multimap.
+ //*********************************************************************
+ void initialise()
+ {
+ pbuckets->resize(pnodepool->max_size());
+
+ if (!empty())
+ {
+ pnodepool->release_all();
+
+ for (size_t i = 0; i < pbuckets->size(); ++i)
+ {
+ (*pbuckets)[i].clear();
+ }
+ }
+
+ first = pbuckets->begin();
+ last = first;
+ }
+
+ private:
+
+ //*********************************************************************
+ /// Adjust the first and last markers according to the new entry.
+ //*********************************************************************
+ void adjust_first_last_markers(bucket_list_iterator ibucket)
+ {
+ if (ibucket < first)
+ {
+ first = ibucket;
+ }
+ else if (ibucket > last)
+ {
+ last = ibucket;
+ }
+ }
+
+ // Disable copy construction.
+ iunordered_multimap(const iunordered_multimap&);
+
+ /// The pool of data nodes used in the list.
+ pool_t* pnodepool;
+
+ /// The bucket list.
+ bucket_list_t* pbuckets;
+
+ /// The first and last iterators to buckets with values.
+ bucket_list_iterator first;
+ bucket_list_iterator last;
+
+ /// The function that creates the hashes.
+ hasher key_hash_function;
+
+ /// The function that compares the keys for equality.
+ key_equal key_equal_function;
+ };
+
+ //***************************************************************************
+ /// Equal operator.
+ ///\param lhs Reference to the first unordered_multimap.
+ ///\param rhs Reference to the second unordered_multimap.
+ ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
+ ///\ingroup unordered_multimap
+ //***************************************************************************
+ template <typename TKey, typename TMapped, typename TKeyCompare>
+ bool operator ==(const etl::iunordered_multimap<TKey, TMapped, TKeyCompare>& lhs, const etl::iunordered_multimap<TKey, TMapped, TKeyCompare>& rhs)
+ {
+ return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin());
+ }
+
+ //***************************************************************************
+ /// Not equal operator.
+ ///\param lhs Reference to the first unordered_multimap.
+ ///\param rhs Reference to the second unordered_multimap.
+ ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
+ ///\ingroup unordered_multimap
+ //***************************************************************************
+ template <typename TKey, typename TMapped, typename TKeyCompare>
+ bool operator !=(const etl::iunordered_multimap<TKey, TMapped, TKeyCompare>& lhs, const etl::iunordered_multimap<TKey, TMapped, TKeyCompare>& rhs)
+ {
+ return !(lhs == rhs);
+ }
+}
+
+#undef ETL_FILE
+#endif
diff --git a/lib/etl/iunordered_multiset.h b/lib/etl/iunordered_multiset.h
new file mode 100644
index 0000000..995836b
--- /dev/null
+++ b/lib/etl/iunordered_multiset.h
@@ -0,0 +1,1183 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_IUNORDERED_MULTISET__
+#define __ETL_IUNORDERED_MULTISET__
+
+#include <iterator>
+#include <algorithm>
+#include <functional>
+#include <utility>
+#include <stddef.h>
+
+#include "type_traits.h"
+#include "parameter_type.h"
+#include "hash.h"
+#include "nullptr.h"
+#include "ipool.h"
+#include "ivector.h"
+#include "error_handler.h"
+#include "intrusive_forward_list.h"
+#include "exception.h"
+#include "error_handler.h"
+
+#undef ETL_FILE
+#define ETL_FILE "26"
+
+namespace etl
+{
+ //***************************************************************************
+ /// Exception for the unordered_multiset.
+ ///\ingroup unordered_multiset
+ //***************************************************************************
+ class unordered_multiset_exception : public exception
+ {
+ public:
+
+ unordered_multiset_exception(string_type what, string_type file_name, numeric_type line_number)
+ : exception(what, file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// Full exception for the unordered_multiset.
+ ///\ingroup unordered_multiset
+ //***************************************************************************
+ class unordered_multiset_full : public unordered_multiset_exception
+ {
+ public:
+
+ unordered_multiset_full(string_type file_name, numeric_type line_number)
+ : unordered_multiset_exception(ETL_ERROR_TEXT("unordered_multiset:full", ETL_FILE"A"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// Out of range exception for the unordered_multiset.
+ ///\ingroup unordered_multiset
+ //***************************************************************************
+ class unordered_multiset_out_of_range : public unordered_multiset_exception
+ {
+ public:
+
+ unordered_multiset_out_of_range(string_type file_name, numeric_type line_number)
+ : unordered_multiset_exception(ETL_ERROR_TEXT("unordered_multiset:range", ETL_FILE"B"), file_name, line_number)
+ {}
+ };
+
+ //***************************************************************************
+ /// Iterator exception for the unordered_multiset.
+ ///\ingroup unordered_multiset
+ //***************************************************************************
+ class unordered_multiset_iterator : public unordered_multiset_exception
+ {
+ public:
+
+ unordered_multiset_iterator(string_type file_name, numeric_type line_number)
+ : unordered_multiset_exception(ETL_ERROR_TEXT("unordered_multiset:iterator", ETL_FILE"C"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// The base class for specifically sized unordered_multiset.
+ /// Can be used as a reference type for all unordered_multiset containing a specific type.
+ ///\ingroup unordered_multiset
+ //***************************************************************************
+ template <typename TKey, typename THash = etl::hash<TKey>, typename TKeyEqual = std::equal_to<TKey> >
+ class iunordered_multiset
+ {
+ public:
+
+ typedef TKey value_type;
+ typedef TKey key_type;
+ typedef THash hasher;
+ typedef TKeyEqual key_equal;
+ typedef value_type& reference;
+ typedef const value_type& const_reference;
+ typedef value_type* pointer;
+ typedef const value_type* const_pointer;
+ typedef size_t size_type;
+
+ typedef typename parameter_type<TKey>::type key_value_parameter_t;
+
+ typedef etl::forward_link<0> link_t;
+
+ // The nodes that store the elements.
+ struct node_t : public link_t
+ {
+ node_t(const value_type& key)
+ : key(key)
+ {
+ }
+
+ value_type key;
+ };
+
+ private:
+
+ typedef etl::intrusive_forward_list<node_t, link_t> bucket_t;
+ typedef etl::ipool<node_t> pool_t;
+ typedef etl::ivector<bucket_t> bucket_list_t;
+
+ typedef typename bucket_list_t::iterator bucket_list_iterator;
+
+ public:
+
+ // Local iterators iterate over one bucket.
+ typedef typename bucket_t::iterator local_iterator;
+ typedef typename bucket_t::const_iterator local_const_iterator;
+
+ //*********************************************************************
+ class iterator : public std::iterator<std::forward_iterator_tag, TKey>
+ {
+ public:
+
+ typedef typename iunordered_multiset::value_type value_type;
+ typedef typename iunordered_multiset::key_type key_type;
+ typedef typename iunordered_multiset::hasher hasher;
+ typedef typename iunordered_multiset::key_equal key_equal;
+ typedef typename iunordered_multiset::reference reference;
+ typedef typename iunordered_multiset::const_reference const_reference;
+ typedef typename iunordered_multiset::pointer pointer;
+ typedef typename iunordered_multiset::const_pointer const_pointer;
+ typedef typename iunordered_multiset::size_type size_type;
+
+ friend class iunordered_multiset;
+
+ //*********************************
+ iterator()
+ {
+ }
+
+ //*********************************
+ iterator(const iterator& other)
+ : ibuckets_end(other.ibuckets_end),
+ ibucket(other.ibucket),
+ inode(other.inode)
+ {
+ }
+
+ //*********************************
+ iterator& operator ++()
+ {
+ ++inode;
+
+ // The end of this node list?
+ if (inode == ibucket->end())
+ {
+ // Search for the next non-empty bucket.
+ ++ibucket;
+ while ((ibucket != ibuckets_end) && (ibucket->empty()))
+ {
+ ++ibucket;
+ }
+
+ // If not past the end, get the first node in the bucket.
+ if (ibucket != ibuckets_end)
+ {
+ inode = ibucket->begin();
+ }
+ }
+
+ return *this;
+ }
+
+ //*********************************
+ iterator operator ++(int)
+ {
+ iterator temp(*this);
+ operator++();
+ return temp;
+ }
+
+ //*********************************
+ iterator operator =(const iterator& other)
+ {
+ ibuckets_end = other.ibuckets_end;
+ ibucket = other.ibucket;
+ inode = other.inode;
+ return *this;
+ }
+
+ //*********************************
+ reference operator *()
+ {
+ return inode->key;
+ }
+
+ //*********************************
+ const_reference operator *() const
+ {
+ return inode->key;
+ }
+
+ //*********************************
+ pointer operator &()
+ {
+ return &(inode->key);
+ }
+
+ //*********************************
+ const_pointer operator &() const
+ {
+ return &(inode->key);
+ }
+
+ //*********************************
+ pointer operator ->()
+ {
+ return &(inode->key);
+ }
+
+ //*********************************
+ const_pointer operator ->() const
+ {
+ return &(inode->key);
+ }
+
+ //*********************************
+ friend bool operator == (const iterator& lhs, const iterator& rhs)
+ {
+ return lhs.compare(rhs);
+ }
+
+ //*********************************
+ friend bool operator != (const iterator& lhs, const iterator& rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+ private:
+
+ //*********************************
+ iterator(bucket_list_iterator ibuckets_end, bucket_list_iterator ibucket, local_iterator inode)
+ : ibuckets_end(ibuckets_end),
+ ibucket(ibucket),
+ inode(inode)
+ {
+ }
+
+ //*********************************
+ bool compare(const iterator& rhs) const
+ {
+ return rhs.inode == inode;
+ }
+
+ //*********************************
+ bucket_t& get_bucket()
+ {
+ return *ibucket;
+ }
+
+ //*********************************
+ bucket_list_iterator& get_bucket_list_iterator()
+ {
+ return ibucket;
+ }
+
+ //*********************************
+ local_iterator get_local_iterator()
+ {
+ return inode;
+ }
+
+ bucket_list_iterator ibuckets_end;
+ bucket_list_iterator ibucket;
+ local_iterator inode;
+ };
+
+ //*********************************************************************
+ class const_iterator : public std::iterator<std::forward_iterator_tag, const TKey>
+ {
+ public:
+
+ typedef typename iunordered_multiset::value_type value_type;
+ typedef typename iunordered_multiset::key_type key_type;
+ typedef typename iunordered_multiset::hasher hasher;
+ typedef typename iunordered_multiset::key_equal key_equal;
+ typedef typename iunordered_multiset::reference reference;
+ typedef typename iunordered_multiset::const_reference const_reference;
+ typedef typename iunordered_multiset::pointer pointer;
+ typedef typename iunordered_multiset::const_pointer const_pointer;
+ typedef typename iunordered_multiset::size_type size_type;
+
+ friend class iunordered_multiset;
+ friend class iterator;
+
+ //*********************************
+ const_iterator()
+ {
+ }
+
+ //*********************************
+ const_iterator(const typename iunordered_multiset::iterator& other)
+ : ibuckets_end(other.ibuckets_end),
+ ibucket(other.ibucket),
+ inode(other.inode)
+ {
+ }
+
+ //*********************************
+ const_iterator(const const_iterator& other)
+ : ibuckets_end(other.ibuckets_end),
+ ibucket(other.ibucket),
+ inode(other.inode)
+ {
+ }
+
+ //*********************************
+ const_iterator& operator ++()
+ {
+ ++inode;
+
+ // The end of this node list?
+ if (inode == ibucket->end())
+ {
+ // Search for the next non-empty bucket.
+
+ ++ibucket;
+ while ((ibucket != ibuckets_end) && (ibucket->empty()))
+ {
+ ++ibucket;
+ }
+
+ // If not past the end, get the first node in the bucket.
+ if (ibucket != ibuckets_end)
+ {
+ inode = ibucket->begin();
+ }
+ }
+
+ return *this;
+ }
+
+ //*********************************
+ const_iterator operator ++(int)
+ {
+ const_iterator temp(*this);
+ operator++();
+ return temp;
+ }
+
+ //*********************************
+ const_iterator operator =(const const_iterator& other)
+ {
+ ibuckets_end = other.ibuckets_end;
+ ibucket = other.ibucket;
+ inode = other.inode;
+ return *this;
+ }
+
+ //*********************************
+ const_reference operator *() const
+ {
+ return inode->key;
+ }
+
+ //*********************************
+ const_pointer operator &() const
+ {
+ return &(inode->key);
+ }
+
+ //*********************************
+ const_pointer operator ->() const
+ {
+ return &(inode->key);
+ }
+
+ //*********************************
+ friend bool operator == (const const_iterator& lhs, const const_iterator& rhs)
+ {
+ return lhs.compare(rhs);
+ }
+
+ //*********************************
+ friend bool operator != (const const_iterator& lhs, const const_iterator& rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+ private:
+
+ //*********************************
+ const_iterator(bucket_list_iterator ibuckets_end, bucket_list_iterator ibucket, local_iterator inode)
+ : ibuckets_end(ibuckets_end),
+ ibucket(ibucket),
+ inode(inode)
+ {
+ }
+
+ //*********************************
+ bool compare(const const_iterator& rhs) const
+ {
+ return rhs.inode == inode;
+ }
+
+ //*********************************
+ bucket_t& get_bucket()
+ {
+ return *ibucket;
+ }
+
+ //*********************************
+ bucket_list_iterator& get_bucket_list_iterator()
+ {
+ return ibucket;
+ }
+
+ //*********************************
+ local_iterator get_local_iterator()
+ {
+ return inode;
+ }
+
+ bucket_list_iterator ibuckets_end;
+ bucket_list_iterator ibucket;
+ local_iterator inode;
+ };
+
+ typedef typename std::iterator_traits<iterator>::difference_type difference_type;
+
+ //*********************************************************************
+ /// Returns an iterator to the beginning of the unordered_multiset.
+ ///\return An iterator to the beginning of the unordered_multiset.
+ //*********************************************************************
+ iterator begin()
+ {
+ return iterator(pbuckets->end(), first, first->begin());
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the beginning of the unordered_multiset.
+ ///\return A const iterator to the beginning of the unordered_multiset.
+ //*********************************************************************
+ const_iterator begin() const
+ {
+ return const_iterator(pbuckets->end(), first, first->begin());
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the beginning of the unordered_multiset.
+ ///\return A const iterator to the beginning of the unordered_multiset.
+ //*********************************************************************
+ const_iterator cbegin() const
+ {
+ return const_iterator(pbuckets->end(), first, first->begin());
+ }
+
+ //*********************************************************************
+ /// Returns an iterator to the beginning of the unordered_multiset bucket.
+ ///\return An iterator to the beginning of the unordered_multiset bucket.
+ //*********************************************************************
+ local_iterator begin(size_t i)
+ {
+ return (*pbuckets)[i].begin();
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the beginning of the unordered_multiset bucket.
+ ///\return A const iterator to the beginning of the unordered_multiset bucket.
+ //*********************************************************************
+ local_const_iterator begin(size_t i) const
+ {
+ return (*pbuckets)[i].cbegin();
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the beginning of the unordered_multiset bucket.
+ ///\return A const iterator to the beginning of the unordered_multiset bucket.
+ //*********************************************************************
+ local_const_iterator cbegin(size_t i) const
+ {
+ return (*pbuckets)[i].cbegin();
+ }
+
+ //*********************************************************************
+ /// Returns an iterator to the end of the unordered_multiset.
+ ///\return An iterator to the end of the unordered_multiset.
+ //*********************************************************************
+ iterator end()
+ {
+ return iterator(pbuckets->end(), last, last->end());
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the end of the unordered_multiset.
+ ///\return A const iterator to the end of the unordered_multiset.
+ //*********************************************************************
+ const_iterator end() const
+ {
+ return const_iterator(pbuckets->end(), last, last->end());
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the end of the unordered_multiset.
+ ///\return A const iterator to the end of the unordered_multiset.
+ //*********************************************************************
+ const_iterator cend() const
+ {
+ return const_iterator(pbuckets->end(), last, last->end());
+ }
+
+ //*********************************************************************
+ /// Returns an iterator to the end of the unordered_multiset bucket.
+ ///\return An iterator to the end of the unordered_multiset bucket.
+ //*********************************************************************
+ local_iterator end(size_t i)
+ {
+ return (*pbuckets)[i].end();
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the end of the unordered_multiset bucket.
+ ///\return A const iterator to the end of the unordered_multiset bucket.
+ //*********************************************************************
+ local_const_iterator end(size_t i) const
+ {
+ return (*pbuckets)[i].cend();
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the end of the unordered_multiset bucket.
+ ///\return A const iterator to the end of the unordered_multiset bucket.
+ //*********************************************************************
+ local_const_iterator cend(size_t i) const
+ {
+ return (*pbuckets)[i].cend();
+ }
+
+ //*********************************************************************
+ /// Returns the bucket index for the key.
+ ///\return The bucket index for the key.
+ //*********************************************************************
+ size_type bucket(key_value_parameter_t key) const
+ {
+ return key_hash_function(key) % pbuckets->size();
+ }
+
+ //*********************************************************************
+ /// Returns the size of the bucket key.
+ ///\return The bucket size of the bucket key.
+ //*********************************************************************
+ size_type bucket_size(key_value_parameter_t key) const
+ {
+ size_t index = bucket(key);
+
+ return std::distance((*pbuckets)[index].begin(), (*pbuckets)[index].end());
+ }
+
+ //*********************************************************************
+ /// Returns the maximum number of the buckets the container can hold.
+ ///\return The maximum number of the buckets the container can hold.
+ //*********************************************************************
+ size_type max_bucket_count() const
+ {
+ return max_size();
+ }
+
+ //*********************************************************************
+ /// Returns the number of the buckets the container holds.
+ ///\return The number of the buckets the container holds.
+ //*********************************************************************
+ size_type bucket_count() const
+ {
+ return max_size();
+ }
+
+ //*********************************************************************
+ /// Assigns values to the unordered_multiset.
+ /// If asserts or exceptions are enabled, emits unordered_multiset_full if the unordered_multiset does not have enough free space.
+ /// If asserts or exceptions are enabled, emits unordered_multiset_iterator if the iterators are reversed.
+ ///\param first The iterator to the first element.
+ ///\param last The iterator to the last element + 1.
+ //*********************************************************************
+ template <typename TIterator>
+ void assign(TIterator first, TIterator last)
+ {
+#ifdef _DEBUG
+ difference_type count = std::distance(first, last);
+ ETL_ASSERT(count >= 0, ETL_ERROR(unordered_multiset_iterator));
+ ETL_ASSERT(size_t(count) <= max_size() , ETL_ERROR(unordered_multiset_full));
+#endif
+
+ clear();
+
+ while (first != last)
+ {
+ insert(*first++);
+ }
+ }
+
+ //*********************************************************************
+ /// Inserts a value to the unordered_multiset.
+ /// If asserts or exceptions are enabled, emits unordered_multiset_full if the unordered_multiset is already full.
+ ///\param value The value to insert.
+ //*********************************************************************
+ std::pair<iterator, bool> insert(const value_type& key)
+ {
+ std::pair<iterator, bool> result(end(), false);
+
+ ETL_ASSERT(!full(), ETL_ERROR(unordered_multiset_full));
+
+ // Get the hash index.
+ size_t index = bucket(key);
+
+ // Get the bucket & bucket iterator.
+ bucket_list_iterator ibucket = pbuckets->begin() + index;
+ bucket_t& bucket = *ibucket;
+
+ // The first one in the bucket?
+ if (bucket.empty())
+ {
+ // Get a new node.
+ node_t& node = *pnodepool->allocate(node_t(key));
+
+ // Just add the pointer to the bucket;
+ bucket.insert_after(bucket.before_begin(), node);
+
+ result.first = iterator(pbuckets->end(), ibucket, ibucket->begin());
+ result.second = true;
+
+ adjust_first_last_markers(ibucket);
+ }
+ else
+ {
+ // Step though the bucket looking for a place to insert.
+ local_iterator inode_previous = bucket.before_begin();
+ local_iterator inode = bucket.begin();
+
+ while (inode != bucket.end())
+ {
+ // Do we already have this key?
+ if (inode->key == key)
+ {
+ break;
+ }
+
+ ++inode_previous;
+ ++inode;
+ }
+
+ // Get a new node.
+ node_t& node = *pnodepool->allocate(node_t(key));
+
+ // Add the node to the end of the bucket;
+ bucket.insert_after(inode_previous, node);
+ ++inode_previous;
+
+ result.first = iterator(pbuckets->end(), ibucket, inode_previous);
+ result.second = true;
+ }
+
+ return result;
+ }
+
+ //*********************************************************************
+ /// Inserts a value to the unordered_multiset.
+ /// If asserts or exceptions are enabled, emits unordered_multiset_full if the unordered_multiset is already full.
+ ///\param position The position to insert at.
+ ///\param value The value to insert.
+ //*********************************************************************
+ iterator insert(const_iterator position, const value_type& key)
+ {
+ return insert(key).first;
+ }
+
+ //*********************************************************************
+ /// Inserts a range of values to the unordered_multiset.
+ /// If asserts or exceptions are enabled, emits unordered_multiset_full if the unordered_multiset does not have enough free space.
+ ///\param position The position to insert at.
+ ///\param first The first element to add.
+ ///\param last The last + 1 element to add.
+ //*********************************************************************
+ template <class TIterator>
+ void insert(TIterator first, TIterator last)
+ {
+ while (first != last)
+ {
+ insert(*first++);
+ }
+ }
+
+ //*********************************************************************
+ /// Erases an element.
+ ///\param key The key to erase.
+ ///\return The number of elements erased.
+ //*********************************************************************
+ size_t erase(key_value_parameter_t key)
+ {
+ size_t count = 0;
+ size_t bucket_id = bucket(key);
+
+ bucket_t& bucket = (*pbuckets)[bucket_id];
+
+ local_iterator iprevious = bucket.before_begin();
+ local_iterator icurrent = bucket.begin();
+
+ while (icurrent != bucket.end())
+ {
+ if (icurrent->key == key)
+ {
+ bucket.erase_after(iprevious);
+ ++count;
+ icurrent = iprevious;
+ }
+ else
+ {
+ ++iprevious;
+ }
+
+ ++icurrent;
+ }
+
+ return count;
+ }
+
+ //*********************************************************************
+ /// Erases an element.
+ ///\param ielement Iterator to the element.
+ //*********************************************************************
+ iterator erase(const_iterator ielement)
+ {
+ // Make a note of the next one.
+ iterator inext(pbuckets->end(), ielement.get_bucket_list_iterator(), ielement.get_local_iterator());
+ ++inext;
+
+ bucket_t& bucket = ielement.get_bucket();
+ local_iterator icurrent = ielement.get_local_iterator();
+ local_iterator iprevious = bucket.before_begin();
+
+ // Find the node we're interested in.
+ while (iprevious->etl_next != &*icurrent)
+ {
+ ++iprevious;
+ }
+
+ bucket.erase_after(iprevious);
+
+ return inext;
+ }
+
+ //*********************************************************************
+ /// Erases a range of elements.
+ /// The range includes all the elements between first and last, including the
+ /// element pointed by first, but not the one pointed to by last.
+ ///\param first Iterator to the first element.
+ ///\param last Iterator to the last element.
+ //*********************************************************************
+ iterator erase(const_iterator first, const_iterator last)
+ {
+ // Make a note of the last.
+ iterator result(pbuckets->end(), last.get_bucket_list_iterator(), last.get_local_iterator());
+
+ // Get the starting point.
+ bucket_list_iterator ibucket = first.get_bucket_list_iterator();
+ local_iterator ifirst = first.get_local_iterator();
+ local_iterator iprevious = ibucket->before_begin();
+ local_iterator iend;
+
+ // Find the first node we're interested in.
+ while (iprevious->etl_next != &*ifirst)
+ {
+ ++iprevious;
+ }
+
+ iend = iprevious;
+ iend++;
+
+ while (first != last)
+ {
+ // Find how far we can go in this bucket.
+ while ((first != last) && (iend != ibucket->end()))
+ {
+ ++first;
+ ++iend;
+ }
+
+ // Erase the range.
+ ibucket->erase_after(iprevious, iend);
+
+ // At the end of this bucket?
+ if (iend == ibucket->end())
+ {
+ // Move on to the next bucket.
+ ++ibucket;
+ iprevious = ibucket->before_begin();
+ iend = iprevious;
+ ++iend;
+ }
+ else
+ {
+ // Still in the same bucket.
+ iprevious = iend;
+ }
+ }
+
+ return result;
+ }
+
+ //*************************************************************************
+ /// Clears the unordered_multiset.
+ //*************************************************************************
+ void clear()
+ {
+ initialise();
+ }
+
+ //*********************************************************************
+ /// Counts an element.
+ ///\param key The key to search for.
+ ///\return 1 if the key exists, otherwise 0.
+ //*********************************************************************
+ size_t count(key_value_parameter_t key) const
+ {
+ size_t n = 0;
+ const_iterator first = find(key);
+ const_iterator last = first;
+
+ if (last != end())
+ {
+ ++last;
+ ++n;
+
+ while ((last != end()) && (key == *last))
+ {
+ ++last;
+ ++n;
+ }
+ }
+
+ return n;
+ }
+
+ //*********************************************************************
+ /// Finds an element.
+ ///\param key The key to search for.
+ ///\return An iterator to the element if the key exists, otherwise end().
+ //*********************************************************************
+ iterator find(key_value_parameter_t key)
+ {
+ size_t index = bucket(key);
+
+ bucket_list_iterator ibucket = pbuckets->begin() + index;
+ bucket_t& bucket = *ibucket;
+
+ // Is the bucket not empty?
+ if (!bucket.empty())
+ {
+ // Step though the list until we find the end or an equivalent key.
+ local_iterator inode = bucket.begin();
+ local_iterator iend = bucket.end();
+
+ while (inode != iend)
+ {
+ // Do we have this one?
+ if (key_equal_function(key, inode->key))
+ {
+ return iterator(pbuckets->end(), ibucket, inode);
+ }
+
+ ++inode;
+ }
+ }
+
+ return end();
+ }
+
+ //*********************************************************************
+ /// Finds an element.
+ ///\param key The key to search for.
+ ///\return An iterator to the element if the key exists, otherwise end().
+ //*********************************************************************
+ const_iterator find(key_value_parameter_t key) const
+ {
+ size_t index = bucket(key);
+
+ bucket_list_iterator ibucket = pbuckets->begin() + index;
+ bucket_t& bucket = *ibucket;
+
+ // Is the bucket not empty?
+ if (!bucket.empty())
+ {
+ // Step though the list until we find the end or an equivalent key.
+ local_iterator inode = bucket.begin();
+ local_iterator iend = bucket.end();
+
+ while (inode != iend)
+ {
+ // Do we have this one?
+ if (key_equal_function(key, inode->key))
+ {
+ return iterator(pbuckets->end(), ibucket, inode);
+ }
+
+ ++inode;
+ }
+ }
+
+ return end();
+ }
+
+ //*********************************************************************
+ /// Returns a range containing all elements with key key in the container.
+ /// The range is defined by two iterators, the first pointing to the first
+ /// element of the wanted range and the second pointing past the last
+ /// element of the range.
+ ///\param key The key to search for.
+ ///\return An iterator pair to the range of elements if the key exists, otherwise end().
+ //*********************************************************************
+ std::pair<iterator, iterator> equal_range(const key_value_parameter_t& key)
+ {
+ iterator first = find(key);
+ iterator last = first;
+
+ if (last != end())
+ {
+ ++last;
+
+ while ((last != end()) && (key == *last))
+ {
+ ++last;
+ }
+ }
+
+ return std::pair<iterator, iterator>(first, last);
+ }
+
+ //*********************************************************************
+ /// Returns a range containing all elements with key key in the container.
+ /// The range is defined by two iterators, the first pointing to the first
+ /// element of the wanted range and the second pointing past the last
+ /// element of the range.
+ ///\param key The key to search for.
+ ///\return A const iterator pair to the range of elements if the key exists, otherwise end().
+ //*********************************************************************
+ std::pair<const_iterator, const_iterator> equal_range(const key_value_parameter_t& key) const
+ {
+ const_iterator first = find(key);
+ const_iterator last = first;
+
+ if (last != end())
+ {
+ ++last;
+
+ while ((last != end()) && (key == *last))
+ {
+ ++last;
+ }
+ }
+
+ return std::pair<const_iterator, const_iterator>(first, last);
+ }
+
+ //*************************************************************************
+ /// Gets the size of the unordered_multiset.
+ //*************************************************************************
+ size_type size() const
+ {
+ return pnodepool->size();
+ }
+
+ //*************************************************************************
+ /// Gets the maximum possible size of the unordered_multiset.
+ //*************************************************************************
+ size_type max_size() const
+ {
+ return pnodepool->max_size();
+ }
+
+ //*************************************************************************
+ /// Checks to see if the unordered_multiset is empty.
+ //*************************************************************************
+ bool empty() const
+ {
+ return pnodepool->empty();
+ }
+
+ //*************************************************************************
+ /// Checks to see if the unordered_multiset is full.
+ //*************************************************************************
+ bool full() const
+ {
+ return pnodepool->full();
+ }
+
+ //*************************************************************************
+ /// Returns the remaining capacity.
+ ///\return The remaining capacity.
+ //*************************************************************************
+ size_t available() const
+ {
+ return pnodepool->available();
+ }
+
+ //*************************************************************************
+ /// Returns the load factor = size / bucket_count.
+ ///\return The load factor = size / bucket_count.
+ //*************************************************************************
+ float load_factor() const
+ {
+ return static_cast<float>(size()) / static_cast<float>(bucket_count());
+ }
+
+ //*************************************************************************
+ /// Returns the function that hashes the keys.
+ ///\return The function that hashes the keys..
+ //*************************************************************************
+ hasher hash_function() const
+ {
+ return key_hash_function;
+ }
+
+ //*************************************************************************
+ /// Returns the function that compares the keys.
+ ///\return The function that compares the keys..
+ //*************************************************************************
+ key_equal key_eq() const
+ {
+ return key_equal_function;
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ iunordered_multiset& operator = (const iunordered_multiset& rhs)
+ {
+ // Skip if doing self assignment
+ if (this != &rhs)
+ {
+ assign(rhs.cbegin(), rhs.cend());
+ }
+
+ return *this;
+ }
+
+ protected:
+
+ //*********************************************************************
+ /// Constructor.
+ //*********************************************************************
+ iunordered_multiset(pool_t& node_pool, bucket_list_t& buckets)
+ : pnodepool(&node_pool),
+ pbuckets(&buckets)
+ {
+ }
+
+ //*********************************************************************
+ /// Initialise the unordered_multiset.
+ //*********************************************************************
+ void initialise()
+ {
+ pbuckets->resize(pnodepool->max_size());
+
+ if (!empty())
+ {
+ pnodepool->release_all();
+
+ for (size_t i = 0; i < pbuckets->size(); ++i)
+ {
+ (*pbuckets)[i].clear();
+ }
+ }
+
+ first = pbuckets->begin();
+ last = first;
+ }
+
+ private:
+
+ //*********************************************************************
+ /// Adjust the first and last markers according to the new entry.
+ //*********************************************************************
+ void adjust_first_last_markers(bucket_list_iterator ibucket)
+ {
+ if (ibucket < first)
+ {
+ first = ibucket;
+ }
+ else if (ibucket > last)
+ {
+ last = ibucket;
+ }
+ }
+
+ // Disable copy construction.
+ iunordered_multiset(const iunordered_multiset&);
+
+ /// The pool of data nodes used in the list.
+ pool_t* pnodepool;
+
+ /// The bucket list.
+ bucket_list_t* pbuckets;
+
+ /// The first and last iterators to buckets with values.
+ bucket_list_iterator first;
+ bucket_list_iterator last;
+
+ /// The function that creates the hashes.
+ hasher key_hash_function;
+
+ /// The function that compares the keys for equality.
+ key_equal key_equal_function;
+ };
+
+ //***************************************************************************
+ /// Equal operator.
+ ///\param lhs Reference to the first unordered_multiset.
+ ///\param rhs Reference to the second unordered_multiset.
+ ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
+ ///\ingroup unordered_multiset
+ //***************************************************************************
+ template <typename TKey, typename TMapped, typename TKeyCompare>
+ bool operator ==(const etl::iunordered_multiset<TKey, TMapped, TKeyCompare>& lhs, const etl::iunordered_multiset<TKey, TMapped, TKeyCompare>& rhs)
+ {
+ return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin());
+ }
+
+ //***************************************************************************
+ /// Not equal operator.
+ ///\param lhs Reference to the first unordered_multiset.
+ ///\param rhs Reference to the second unordered_multiset.
+ ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
+ ///\ingroup unordered_multiset
+ //***************************************************************************
+ template <typename TKey, typename TMapped, typename TKeyCompare>
+ bool operator !=(const etl::iunordered_multiset<TKey, TMapped, TKeyCompare>& lhs, const etl::iunordered_multiset<TKey, TMapped, TKeyCompare>& rhs)
+ {
+ return !(lhs == rhs);
+ }
+}
+
+#undef ETL_FILE
+#endif
diff --git a/lib/etl/iunordered_set.h b/lib/etl/iunordered_set.h
new file mode 100644
index 0000000..e11ac9c
--- /dev/null
+++ b/lib/etl/iunordered_set.h
@@ -0,0 +1,1157 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_IUNORDERED_SET__
+#define __ETL_IUNORDERED_SET__
+
+#include <iterator>
+#include <algorithm>
+#include <functional>
+#include <utility>
+#include <stddef.h>
+
+#include "type_traits.h"
+#include "parameter_type.h"
+#include "hash.h"
+#include "nullptr.h"
+#include "ipool.h"
+#include "ivector.h"
+#include "error_handler.h"
+#include "intrusive_forward_list.h"
+#include "exception.h"
+#include "error_handler.h"
+
+#undef ETL_FILE
+#define ETL_FILE "23"
+
+namespace etl
+{
+ //***************************************************************************
+ /// Exception for the unordered_set.
+ ///\ingroup unordered_set
+ //***************************************************************************
+ class unordered_set_exception : public exception
+ {
+ public:
+
+ unordered_set_exception(string_type what, string_type file_name, numeric_type line_number)
+ : exception(what, file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// Full exception for the unordered_set.
+ ///\ingroup unordered_set
+ //***************************************************************************
+ class unordered_set_full : public unordered_set_exception
+ {
+ public:
+
+ unordered_set_full(string_type file_name, numeric_type line_number)
+ : unordered_set_exception(ETL_ERROR_TEXT("unordered_set:full", ETL_FILE"A"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// Out of range exception for the unordered_set.
+ ///\ingroup unordered_set
+ //***************************************************************************
+ class unordered_set_out_of_range : public unordered_set_exception
+ {
+ public:
+
+ unordered_set_out_of_range(string_type file_name, numeric_type line_number)
+ : unordered_set_exception(ETL_ERROR_TEXT("unordered_set:range", ETL_FILE"B"), file_name, line_number)
+ {}
+ };
+
+ //***************************************************************************
+ /// Iterator exception for the unordered_set.
+ ///\ingroup unordered_set
+ //***************************************************************************
+ class unordered_set_iterator : public unordered_set_exception
+ {
+ public:
+
+ unordered_set_iterator(string_type file_name, numeric_type line_number)
+ : unordered_set_exception(ETL_ERROR_TEXT("unordered_set:iterator", ETL_FILE"C"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// The base class for specifically sized unordered_set.
+ /// Can be used as a reference type for all unordered_set containing a specific type.
+ ///\ingroup unordered_set
+ //***************************************************************************
+ template <typename TKey, typename THash = etl::hash<TKey>, typename TKeyEqual = std::equal_to<TKey> >
+ class iunordered_set
+ {
+ public:
+
+ typedef TKey value_type;
+ typedef TKey key_type;
+ typedef THash hasher;
+ typedef TKeyEqual key_equal;
+ typedef value_type& reference;
+ typedef const value_type& const_reference;
+ typedef value_type* pointer;
+ typedef const value_type* const_pointer;
+ typedef size_t size_type;
+
+ typedef typename parameter_type<TKey>::type key_value_parameter_t;
+
+ typedef etl::forward_link<0> link_t;
+
+ // The nodes that store the elements.
+ struct node_t : public link_t
+ {
+ node_t(const value_type& key)
+ : key(key)
+ {
+ }
+
+ value_type key;
+ };
+
+ private:
+
+ typedef etl::intrusive_forward_list<node_t, link_t> bucket_t;
+ typedef etl::ipool<node_t> pool_t;
+ typedef etl::ivector<bucket_t> bucket_list_t;
+
+ typedef typename bucket_list_t::iterator bucket_list_iterator;
+
+ public:
+
+ // Local iterators iterate over one bucket.
+ typedef typename bucket_t::iterator local_iterator;
+ typedef typename bucket_t::const_iterator local_const_iterator;
+
+ //*********************************************************************
+ class iterator : public std::iterator<std::forward_iterator_tag, TKey>
+ {
+ public:
+
+ typedef typename iunordered_set::value_type value_type;
+ typedef typename iunordered_set::key_type key_type;
+ typedef typename iunordered_set::hasher hasher;
+ typedef typename iunordered_set::key_equal key_equal;
+ typedef typename iunordered_set::reference reference;
+ typedef typename iunordered_set::const_reference const_reference;
+ typedef typename iunordered_set::pointer pointer;
+ typedef typename iunordered_set::const_pointer const_pointer;
+ typedef typename iunordered_set::size_type size_type;
+
+ friend class iunordered_set;
+
+ //*********************************
+ iterator()
+ {
+ }
+
+ //*********************************
+ iterator(const iterator& other)
+ : ibuckets_end(other.ibuckets_end),
+ ibucket(other.ibucket),
+ inode(other.inode)
+ {
+ }
+
+ //*********************************
+ iterator& operator ++()
+ {
+ ++inode;
+
+ // The end of this node list?
+ if (inode == ibucket->end())
+ {
+ // Search for the next non-empty bucket.
+ ++ibucket;
+ while ((ibucket != ibuckets_end) && (ibucket->empty()))
+ {
+ ++ibucket;
+ }
+
+ // If not past the end, get the first node in the bucket.
+ if (ibucket != ibuckets_end)
+ {
+ inode = ibucket->begin();
+ }
+ }
+
+ return *this;
+ }
+
+ //*********************************
+ iterator operator ++(int)
+ {
+ iterator temp(*this);
+ operator++();
+ return temp;
+ }
+
+ //*********************************
+ iterator operator =(const iterator& other)
+ {
+ ibuckets_end = other.ibuckets_end;
+ ibucket = other.ibucket;
+ inode = other.inode;
+ return *this;
+ }
+
+ //*********************************
+ reference operator *()
+ {
+ return inode->key;
+ }
+
+ //*********************************
+ const_reference operator *() const
+ {
+ return inode->key;
+ }
+
+ //*********************************
+ pointer operator &()
+ {
+ return &(inode->key);
+ }
+
+ //*********************************
+ const_pointer operator &() const
+ {
+ return &(inode->key);
+ }
+
+ //*********************************
+ pointer operator ->()
+ {
+ return &(inode->key);
+ }
+
+ //*********************************
+ const_pointer operator ->() const
+ {
+ return &(inode->key);
+ }
+
+ //*********************************
+ friend bool operator == (const iterator& lhs, const iterator& rhs)
+ {
+ return lhs.compare(rhs);
+ }
+
+ //*********************************
+ friend bool operator != (const iterator& lhs, const iterator& rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+ private:
+
+ //*********************************
+ iterator(bucket_list_iterator ibuckets_end, bucket_list_iterator ibucket, local_iterator inode)
+ : ibuckets_end(ibuckets_end),
+ ibucket(ibucket),
+ inode(inode)
+ {
+ }
+
+ //*********************************
+ bool compare(const iterator& rhs) const
+ {
+ return rhs.inode == inode;
+ }
+
+ //*********************************
+ bucket_t& get_bucket()
+ {
+ return *ibucket;
+ }
+
+ //*********************************
+ bucket_list_iterator& get_bucket_list_iterator()
+ {
+ return ibucket;
+ }
+
+ //*********************************
+ local_iterator get_local_iterator()
+ {
+ return inode;
+ }
+
+ bucket_list_iterator ibuckets_end;
+ bucket_list_iterator ibucket;
+ local_iterator inode;
+ };
+
+ //*********************************************************************
+ class const_iterator : public std::iterator<std::forward_iterator_tag, const TKey>
+ {
+ public:
+
+ typedef typename iunordered_set::value_type value_type;
+ typedef typename iunordered_set::key_type key_type;
+ typedef typename iunordered_set::hasher hasher;
+ typedef typename iunordered_set::key_equal key_equal;
+ typedef typename iunordered_set::reference reference;
+ typedef typename iunordered_set::const_reference const_reference;
+ typedef typename iunordered_set::pointer pointer;
+ typedef typename iunordered_set::const_pointer const_pointer;
+ typedef typename iunordered_set::size_type size_type;
+
+ friend class iunordered_set;
+ friend class iterator;
+
+ //*********************************
+ const_iterator()
+ {
+ }
+
+ //*********************************
+ const_iterator(const typename iunordered_set::iterator& other)
+ : ibuckets_end(other.ibuckets_end),
+ ibucket(other.ibucket),
+ inode(other.inode)
+ {
+ }
+
+ //*********************************
+ const_iterator(const const_iterator& other)
+ : ibuckets_end(other.ibuckets_end),
+ ibucket(other.ibucket),
+ inode(other.inode)
+ {
+ }
+
+ //*********************************
+ const_iterator& operator ++()
+ {
+ ++inode;
+
+ // The end of this node list?
+ if (inode == ibucket->end())
+ {
+ // Search for the next non-empty bucket.
+
+ ++ibucket;
+ while ((ibucket != ibuckets_end) && (ibucket->empty()))
+ {
+ ++ibucket;
+ }
+
+ // If not past the end, get the first node in the bucket.
+ if (ibucket != ibuckets_end)
+ {
+ inode = ibucket->begin();
+ }
+ }
+
+ return *this;
+ }
+
+ //*********************************
+ const_iterator operator ++(int)
+ {
+ const_iterator temp(*this);
+ operator++();
+ return temp;
+ }
+
+ //*********************************
+ const_iterator operator =(const const_iterator& other)
+ {
+ ibuckets_end = other.ibuckets_end;
+ ibucket = other.ibucket;
+ inode = other.inode;
+ return *this;
+ }
+
+ //*********************************
+ const_reference operator *() const
+ {
+ return inode->key;
+ }
+
+ //*********************************
+ const_pointer operator &() const
+ {
+ return &(inode->key);
+ }
+
+ //*********************************
+ const_pointer operator ->() const
+ {
+ return &(inode->key);
+ }
+
+ //*********************************
+ friend bool operator == (const const_iterator& lhs, const const_iterator& rhs)
+ {
+ return lhs.compare(rhs);
+ }
+
+ //*********************************
+ friend bool operator != (const const_iterator& lhs, const const_iterator& rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+ private:
+
+ //*********************************
+ const_iterator(bucket_list_iterator ibuckets_end, bucket_list_iterator ibucket, local_iterator inode)
+ : ibuckets_end(ibuckets_end),
+ ibucket(ibucket),
+ inode(inode)
+ {
+ }
+
+ //*********************************
+ bool compare(const const_iterator& rhs) const
+ {
+ return rhs.inode == inode;
+ }
+
+ //*********************************
+ bucket_t& get_bucket()
+ {
+ return *ibucket;
+ }
+
+ //*********************************
+ bucket_list_iterator& get_bucket_list_iterator()
+ {
+ return ibucket;
+ }
+
+ //*********************************
+ local_iterator get_local_iterator()
+ {
+ return inode;
+ }
+
+ bucket_list_iterator ibuckets_end;
+ bucket_list_iterator ibucket;
+ local_iterator inode;
+ };
+
+ typedef typename std::iterator_traits<iterator>::difference_type difference_type;
+
+ //*********************************************************************
+ /// Returns an iterator to the beginning of the unordered_set.
+ ///\return An iterator to the beginning of the unordered_set.
+ //*********************************************************************
+ iterator begin()
+ {
+ return iterator(pbuckets->end(), first, first->begin());
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the beginning of the unordered_set.
+ ///\return A const iterator to the beginning of the unordered_set.
+ //*********************************************************************
+ const_iterator begin() const
+ {
+ return const_iterator(pbuckets->end(), first, first->begin());
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the beginning of the unordered_set.
+ ///\return A const iterator to the beginning of the unordered_set.
+ //*********************************************************************
+ const_iterator cbegin() const
+ {
+ return const_iterator(pbuckets->end(), first, first->begin());
+ }
+
+ //*********************************************************************
+ /// Returns an iterator to the beginning of the unordered_set bucket.
+ ///\return An iterator to the beginning of the unordered_set bucket.
+ //*********************************************************************
+ local_iterator begin(size_t i)
+ {
+ return (*pbuckets)[i].begin();
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the beginning of the unordered_set bucket.
+ ///\return A const iterator to the beginning of the unordered_set bucket.
+ //*********************************************************************
+ local_const_iterator begin(size_t i) const
+ {
+ return (*pbuckets)[i].cbegin();
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the beginning of the unordered_set bucket.
+ ///\return A const iterator to the beginning of the unordered_set bucket.
+ //*********************************************************************
+ local_const_iterator cbegin(size_t i) const
+ {
+ return (*pbuckets)[i].cbegin();
+ }
+
+ //*********************************************************************
+ /// Returns an iterator to the end of the unordered_set.
+ ///\return An iterator to the end of the unordered_set.
+ //*********************************************************************
+ iterator end()
+ {
+ return iterator(pbuckets->end(), last, last->end());
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the end of the unordered_set.
+ ///\return A const iterator to the end of the unordered_set.
+ //*********************************************************************
+ const_iterator end() const
+ {
+ return const_iterator(pbuckets->end(), last, last->end());
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the end of the unordered_set.
+ ///\return A const iterator to the end of the unordered_set.
+ //*********************************************************************
+ const_iterator cend() const
+ {
+ return const_iterator(pbuckets->end(), last, last->end());
+ }
+
+ //*********************************************************************
+ /// Returns an iterator to the end of the unordered_set bucket.
+ ///\return An iterator to the end of the unordered_set bucket.
+ //*********************************************************************
+ local_iterator end(size_t i)
+ {
+ return (*pbuckets)[i].end();
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the end of the unordered_set bucket.
+ ///\return A const iterator to the end of the unordered_set bucket.
+ //*********************************************************************
+ local_const_iterator end(size_t i) const
+ {
+ return (*pbuckets)[i].cend();
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the end of the unordered_set bucket.
+ ///\return A const iterator to the end of the unordered_set bucket.
+ //*********************************************************************
+ local_const_iterator cend(size_t i) const
+ {
+ return (*pbuckets)[i].cend();
+ }
+
+ //*********************************************************************
+ /// Returns the bucket index for the key.
+ ///\return The bucket index for the key.
+ //*********************************************************************
+ size_type bucket(key_value_parameter_t key) const
+ {
+ return key_hash_function(key) % pbuckets->size();
+ }
+
+ //*********************************************************************
+ /// Returns the size of the bucket key.
+ ///\return The bucket size of the bucket key.
+ //*********************************************************************
+ size_type bucket_size(key_value_parameter_t key) const
+ {
+ size_t index = bucket(key);
+
+ return std::distance((*pbuckets)[index].begin(), (*pbuckets)[index].end());
+ }
+
+ //*********************************************************************
+ /// Returns the maximum number of the buckets the container can hold.
+ ///\return The maximum number of the buckets the container can hold.
+ //*********************************************************************
+ size_type max_bucket_count() const
+ {
+ return max_size();
+ }
+
+ //*********************************************************************
+ /// Returns the number of the buckets the container holds.
+ ///\return The number of the buckets the container holds.
+ //*********************************************************************
+ size_type bucket_count() const
+ {
+ return max_size();
+ }
+
+ //*********************************************************************
+ /// Assigns values to the unordered_set.
+ /// If asserts or exceptions are enabled, emits unordered_set_full if the unordered_set does not have enough free space.
+ /// If asserts or exceptions are enabled, emits unordered_set_iterator if the iterators are reversed.
+ ///\param first The iterator to the first element.
+ ///\param last The iterator to the last element + 1.
+ //*********************************************************************
+ template <typename TIterator>
+ void assign(TIterator first, TIterator last)
+ {
+#ifdef _DEBUG
+ difference_type count = std::distance(first, last);
+ ETL_ASSERT(count >= 0, ETL_ERROR(unordered_set_iterator));
+ ETL_ASSERT(size_t(count) <= max_size() , ETL_ERROR(unordered_set_full));
+#endif
+
+ clear();
+
+ while (first != last)
+ {
+ insert(*first++);
+ }
+ }
+
+ //*********************************************************************
+ /// Inserts a value to the unordered_set.
+ /// If asserts or exceptions are enabled, emits unordered_set_full if the unordered_set is already full.
+ ///\param value The value to insert.
+ //*********************************************************************
+ std::pair<iterator, bool> insert(const value_type& key)
+ {
+ std::pair<iterator, bool> result(end(), false);
+
+ ETL_ASSERT(!full(), ETL_ERROR(unordered_set_full));
+
+ // Get the hash index.
+ size_t index = bucket(key);
+
+ // Get the bucket & bucket iterator.
+ bucket_list_iterator ibucket = pbuckets->begin() + index;
+ bucket_t& bucket = *ibucket;
+
+ // The first one in the bucket?
+ if (bucket.empty())
+ {
+ // Get a new node.
+ node_t& node = *pnodepool->allocate(node_t(key));
+
+ // Just add the pointer to the bucket;
+ bucket.insert_after(bucket.before_begin(), node);
+
+ result.first = iterator(pbuckets->end(), ibucket, ibucket->begin());
+ result.second = true;
+
+ adjust_first_last_markers(ibucket);
+ }
+ else
+ {
+ // Step though the bucket looking for a place to insert.
+ local_iterator inode_previous = bucket.before_begin();
+ local_iterator inode = bucket.begin();
+
+ while (inode != bucket.end())
+ {
+ // Do we already have this key?
+ if (inode->key == key)
+ {
+ break;
+ }
+
+ ++inode_previous;
+ ++inode;
+ }
+
+ // Not already there?
+ if (inode == bucket.end())
+ {
+ // Get a new node.
+ node_t& node = *pnodepool->allocate(node_t(key));
+
+ // Add the node to the end of the bucket;
+ bucket.insert_after(inode_previous, node);
+ ++inode_previous;
+
+ result.first = iterator(pbuckets->end(), ibucket, inode_previous);
+ result.second = true;
+ }
+ }
+
+ return result;
+ }
+
+ //*********************************************************************
+ /// Inserts a value to the unordered_set.
+ /// If asserts or exceptions are enabled, emits unordered_set_full if the unordered_set is already full.
+ ///\param position The position to insert at.
+ ///\param value The value to insert.
+ //*********************************************************************
+ iterator insert(const_iterator position, const value_type& key)
+ {
+ return insert(key).first;
+ }
+
+ //*********************************************************************
+ /// Inserts a range of values to the unordered_set.
+ /// If asserts or exceptions are enabled, emits unordered_set_full if the unordered_set does not have enough free space.
+ ///\param position The position to insert at.
+ ///\param first The first element to add.
+ ///\param last The last + 1 element to add.
+ //*********************************************************************
+ template <class TIterator>
+ void insert(TIterator first, TIterator last)
+ {
+ while (first != last)
+ {
+ insert(*first++);
+ }
+ }
+
+ //*********************************************************************
+ /// Erases an element.
+ ///\param key The key to erase.
+ ///\return The number of elements erased. 0 or 1.
+ //*********************************************************************
+ size_t erase(key_value_parameter_t key)
+ {
+ size_t count = 0;
+ size_t bucket_id = bucket(key);
+
+ bucket_t& bucket = (*pbuckets)[bucket_id];
+
+ local_iterator iprevious = bucket.before_begin();
+ local_iterator icurrent = bucket.begin();
+
+ while ((icurrent != bucket.end()) && (icurrent->key != key))
+ {
+ ++iprevious;
+ ++icurrent;
+ }
+
+ if (icurrent != bucket.end())
+ {
+ bucket.erase_after(iprevious);
+ count = 1;
+ }
+
+ return count;
+ }
+
+ //*********************************************************************
+ /// Erases an element.
+ ///\param ielement Iterator to the element.
+ //*********************************************************************
+ iterator erase(const_iterator ielement)
+ {
+ // Make a note of the next one.
+ iterator inext(pbuckets->end(), ielement.get_bucket_list_iterator(), ielement.get_local_iterator());
+ ++inext;
+
+ bucket_t& bucket = ielement.get_bucket();
+ local_iterator icurrent = ielement.get_local_iterator();
+ local_iterator iprevious = bucket.before_begin();
+
+ // Find the node we're interested in.
+ while (iprevious->etl_next != &*icurrent)
+ {
+ ++iprevious;
+ }
+
+ bucket.erase_after(iprevious);
+
+ return inext;
+ }
+
+ //*********************************************************************
+ /// Erases a range of elements.
+ /// The range includes all the elements between first and last, including the
+ /// element pointed by first, but not the one pointed to by last.
+ ///\param first Iterator to the first element.
+ ///\param last Iterator to the last element.
+ //*********************************************************************
+ iterator erase(const_iterator first, const_iterator last)
+ {
+ // Make a note of the last.
+ iterator result(pbuckets->end(), last.get_bucket_list_iterator(), last.get_local_iterator());
+
+ // Get the starting point.
+ bucket_list_iterator ibucket = first.get_bucket_list_iterator();
+ local_iterator ifirst = first.get_local_iterator();
+ local_iterator iprevious = ibucket->before_begin();
+ local_iterator iend;
+
+ // Find the first node we're interested in.
+ while (iprevious->etl_next != &*ifirst)
+ {
+ ++iprevious;
+ }
+
+ iend = iprevious;
+ iend++;
+
+ while (first != last)
+ {
+ // Find how far we can go in this bucket.
+ while ((first != last) && (iend != ibucket->end()))
+ {
+ ++first;
+ ++iend;
+ }
+
+ // Erase the range.
+ ibucket->erase_after(iprevious, iend);
+
+ // At the end of this bucket?
+ if (iend == ibucket->end())
+ {
+ // Move on to the next bucket.
+ ++ibucket;
+ iprevious = ibucket->before_begin();
+ iend = iprevious;
+ ++iend;
+ }
+ else
+ {
+ // Still in the same bucket.
+ iprevious = iend;
+ }
+ }
+
+ return result;
+ }
+
+ //*************************************************************************
+ /// Clears the unordered_set.
+ //*************************************************************************
+ void clear()
+ {
+ initialise();
+ }
+
+ //*********************************************************************
+ /// Counts an element.
+ ///\param key The key to search for.
+ ///\return 1 if the key exists, otherwise 0.
+ //*********************************************************************
+ size_t count(key_value_parameter_t key) const
+ {
+ return (find(key) == end()) ? 0 : 1;
+ }
+
+ //*********************************************************************
+ /// Finds an element.
+ ///\param key The key to search for.
+ ///\return An iterator to the element if the key exists, otherwise end().
+ //*********************************************************************
+ iterator find(key_value_parameter_t key)
+ {
+ size_t index = bucket(key);
+
+ bucket_list_iterator ibucket = pbuckets->begin() + index;
+ bucket_t& bucket = *ibucket;
+
+ // Is the bucket not empty?
+ if (!bucket.empty())
+ {
+ // Step though the list until we find the end or an equivalent key.
+ local_iterator inode = bucket.begin();
+ local_iterator iend = bucket.end();
+
+ while (inode != iend)
+ {
+ // Do we have this one?
+ if (key_equal_function(key, inode->key))
+ {
+ return iterator(pbuckets->end(), ibucket, inode);
+ }
+
+ ++inode;
+ }
+ }
+
+ return end();
+ }
+
+ //*********************************************************************
+ /// Finds an element.
+ ///\param key The key to search for.
+ ///\return An iterator to the element if the key exists, otherwise end().
+ //*********************************************************************
+ const_iterator find(key_value_parameter_t key) const
+ {
+ size_t index = bucket(key);
+
+ bucket_list_iterator ibucket = pbuckets->begin() + index;
+ bucket_t& bucket = *ibucket;
+
+ // Is the bucket not empty?
+ if (!bucket.empty())
+ {
+ // Step though the list until we find the end or an equivalent key.
+ local_iterator inode = bucket.begin();
+ local_iterator iend = bucket.end();
+
+ while (inode != iend)
+ {
+ // Do we have this one?
+ if (key_equal_function(key, inode->key))
+ {
+ return iterator(pbuckets->end(), ibucket, inode);
+ }
+
+ ++inode;
+ }
+ }
+
+ return end();
+ }
+
+ //*********************************************************************
+ /// Returns a range containing all elements with key 'key' in the container.
+ /// The range is defined by two iterators, the first pointing to the first
+ /// element of the wanted range and the second pointing past the last
+ /// element of the range.
+ ///\param key The key to search for.
+ ///\return An iterator pair to the range of elements if the key exists, otherwise end().
+ //*********************************************************************
+ std::pair<iterator, iterator> equal_range(const key_value_parameter_t& key)
+ {
+ iterator first = find(key);
+ iterator last = first;
+
+ if (last != end())
+ {
+ ++last;
+ }
+
+ return std::pair<iterator, iterator>(first, last);
+ }
+
+ //*********************************************************************
+ /// Returns a range containing all elements with key 'key' in the container.
+ /// The range is defined by two iterators, the first pointing to the first
+ /// element of the wanted range and the second pointing past the last
+ /// element of the range.
+ ///\param key The key to search for.
+ ///\return A const iterator pair to the range of elements if the key exists, otherwise end().
+ //*********************************************************************
+ std::pair<const_iterator, const_iterator> equal_range(const key_value_parameter_t& key) const
+ {
+ const_iterator first = find(key);
+ const_iterator last = first;
+
+ if (last != end())
+ {
+ ++last;
+ }
+
+ return std::pair<const_iterator, const_iterator>(first, last);
+ }
+
+ //*************************************************************************
+ /// Gets the size of the unordered_set.
+ //*************************************************************************
+ size_type size() const
+ {
+ return pnodepool->size();
+ }
+
+ //*************************************************************************
+ /// Gets the maximum possible size of the unordered_set.
+ //*************************************************************************
+ size_type max_size() const
+ {
+ return pnodepool->max_size();
+ }
+
+ //*************************************************************************
+ /// Checks to see if the unordered_set is empty.
+ //*************************************************************************
+ bool empty() const
+ {
+ return pnodepool->empty();
+ }
+
+ //*************************************************************************
+ /// Checks to see if the unordered_set is full.
+ //*************************************************************************
+ bool full() const
+ {
+ return pnodepool->full();
+ }
+
+ //*************************************************************************
+ /// Returns the remaining capacity.
+ ///\return The remaining capacity.
+ //*************************************************************************
+ size_t available() const
+ {
+ return pnodepool->available();
+ }
+
+ //*************************************************************************
+ /// Returns the load factor = size / bucket_count.
+ ///\return The load factor = size / bucket_count.
+ //*************************************************************************
+ float load_factor() const
+ {
+ return static_cast<float>(size()) / static_cast<float>(bucket_count());
+ }
+
+ //*************************************************************************
+ /// Returns the function that hashes the keys.
+ ///\return The function that hashes the keys..
+ //*************************************************************************
+ hasher hash_function() const
+ {
+ return key_hash_function;
+ }
+
+ //*************************************************************************
+ /// Returns the function that compares the keys.
+ ///\return The function that compares the keys..
+ //*************************************************************************
+ key_equal key_eq() const
+ {
+ return key_equal_function;
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ iunordered_set& operator = (const iunordered_set& rhs)
+ {
+ // Skip if doing self assignment
+ if (this != &rhs)
+ {
+ assign(rhs.cbegin(), rhs.cend());
+ }
+
+ return *this;
+ }
+
+ protected:
+
+ //*********************************************************************
+ /// Constructor.
+ //*********************************************************************
+ iunordered_set(pool_t& node_pool, bucket_list_t& buckets)
+ : pnodepool(&node_pool),
+ pbuckets(&buckets)
+ {
+ }
+
+ //*********************************************************************
+ /// Initialise the unordered_set.
+ //*********************************************************************
+ void initialise()
+ {
+ pbuckets->resize(pnodepool->max_size());
+
+ if (!empty())
+ {
+ pnodepool->release_all();
+
+ for (size_t i = 0; i < pbuckets->size(); ++i)
+ {
+ (*pbuckets)[i].clear();
+ }
+ }
+
+ first = pbuckets->begin();
+ last = first;
+ }
+
+ private:
+
+ //*********************************************************************
+ /// Adjust the first and last markers according to the new entry.
+ //*********************************************************************
+ void adjust_first_last_markers(bucket_list_iterator ibucket)
+ {
+ if (ibucket < first)
+ {
+ first = ibucket;
+ }
+ else if (ibucket > last)
+ {
+ last = ibucket;
+ }
+ }
+
+ // Disable copy construction.
+ iunordered_set(const iunordered_set&);
+
+ /// The pool of data nodes used in the list.
+ pool_t* pnodepool;
+
+ /// The bucket list.
+ bucket_list_t* pbuckets;
+
+ /// The first and last iterators to buckets with values.
+ bucket_list_iterator first;
+ bucket_list_iterator last;
+
+ /// The function that creates the hashes.
+ hasher key_hash_function;
+
+ /// The function that compares the keys for equality.
+ key_equal key_equal_function;
+ };
+
+ //***************************************************************************
+ /// Equal operator.
+ ///\param lhs Reference to the first unordered_set.
+ ///\param rhs Reference to the second unordered_set.
+ ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
+ ///\ingroup unordered_set
+ //***************************************************************************
+ template <typename TKey, typename TMapped, typename TKeyCompare>
+ bool operator ==(const etl::iunordered_set<TKey, TMapped, TKeyCompare>& lhs, const etl::iunordered_set<TKey, TMapped, TKeyCompare>& rhs)
+ {
+ return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin());
+ }
+
+ //***************************************************************************
+ /// Not equal operator.
+ ///\param lhs Reference to the first unordered_set.
+ ///\param rhs Reference to the second unordered_set.
+ ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
+ ///\ingroup unordered_set
+ //***************************************************************************
+ template <typename TKey, typename TMapped, typename TKeyCompare>
+ bool operator !=(const etl::iunordered_set<TKey, TMapped, TKeyCompare>& lhs, const etl::iunordered_set<TKey, TMapped, TKeyCompare>& rhs)
+ {
+ return !(lhs == rhs);
+ }
+}
+
+#undef ETL_FILE
+#endif
diff --git a/lib/etl/ivector.h b/lib/etl/ivector.h
new file mode 100644
index 0000000..0dfe849
--- /dev/null
+++ b/lib/etl/ivector.h
@@ -0,0 +1,907 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_IVECTOR__
+#define __ETL_IVECTOR__
+#define __ETL_IN_IVECTOR_H__
+
+#include <iterator>
+#include <algorithm>
+#include <functional>
+#include <stddef.h>
+
+#include "platform.h"
+#include "algorithm.h"
+#include "private/vector_base.h"
+#include "type_traits.h"
+#include "parameter_type.h"
+#include "error_handler.h"
+
+#ifdef ETL_COMPILER_GCC
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#endif
+
+namespace etl
+{
+ //***************************************************************************
+ /// The base class for specifically sized vectors.
+ /// Can be used as a reference type for all vectors containing a specific type.
+ ///\ingroup vector
+ //***************************************************************************
+ template <typename T>
+ class ivector : public vector_base
+ {
+ public:
+
+ typedef T value_type;
+ typedef T& reference;
+ typedef const T& const_reference;
+ typedef T* pointer;
+ typedef const T* const_pointer;
+ typedef T* iterator;
+ typedef const T* const_iterator;
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+ typedef size_t size_type;
+ typedef typename std::iterator_traits<iterator>::difference_type difference_type;
+
+ private:
+
+ // Type trait to allow selection of simple algorithms for simple types.
+ template <typename U>
+ struct is_simple_type : integral_constant<bool, etl::is_fundamental<U>::value || etl::is_pointer<U>::value>
+ {
+ };
+
+ protected:
+
+ typedef typename parameter_type<T>::type parameter_t;
+
+ public:
+
+ //*********************************************************************
+ /// Returns an iterator to the beginning of the vector.
+ ///\return An iterator to the beginning of the vector.
+ //*********************************************************************
+ iterator begin()
+ {
+ return &p_buffer[0];
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the beginning of the vector.
+ ///\return A const iterator to the beginning of the vector.
+ //*********************************************************************
+ const_iterator begin() const
+ {
+ return &p_buffer[0];
+ }
+
+ //*********************************************************************
+ /// Returns an iterator to the end of the vector.
+ ///\return An iterator to the end of the vector.
+ //*********************************************************************
+ iterator end()
+ {
+ return &p_buffer[current_size];
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the end of the vector.
+ ///\return A const iterator to the end of the vector.
+ //*********************************************************************
+ const_iterator end() const
+ {
+ return &p_buffer[current_size];
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the beginning of the vector.
+ ///\return A const iterator to the beginning of the vector.
+ //*********************************************************************
+ const_iterator cbegin() const
+ {
+ return &p_buffer[0];
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the end of the vector.
+ ///\return A const iterator to the end of the vector.
+ //*********************************************************************
+ const_iterator cend() const
+ {
+ return &p_buffer[current_size];
+ }
+
+ //*********************************************************************
+ /// Returns an reverse iterator to the reverse beginning of the vector.
+ ///\return Iterator to the reverse beginning of the vector.
+ //*********************************************************************
+ reverse_iterator rbegin()
+ {
+ return reverse_iterator(end());
+ }
+
+ //*********************************************************************
+ /// Returns a const reverse iterator to the reverse beginning of the vector.
+ ///\return Const iterator to the reverse beginning of the vector.
+ //*********************************************************************
+ const_reverse_iterator rbegin() const
+ {
+ return const_reverse_iterator(end());
+ }
+
+ //*********************************************************************
+ /// Returns a reverse iterator to the end + 1 of the vector.
+ ///\return Reverse iterator to the end + 1 of the vector.
+ //*********************************************************************
+ reverse_iterator rend()
+ {
+ return reverse_iterator(begin());
+ }
+
+ //*********************************************************************
+ /// Returns a const reverse iterator to the end + 1 of the vector.
+ ///\return Const reverse iterator to the end + 1 of the vector.
+ //*********************************************************************
+ const_reverse_iterator rend() const
+ {
+ return const_reverse_iterator(begin());
+ }
+
+ //*********************************************************************
+ /// Returns a const reverse iterator to the reverse beginning of the vector.
+ ///\return Const reverse iterator to the reverse beginning of the vector.
+ //*********************************************************************
+ const_reverse_iterator crbegin() const
+ {
+ return const_reverse_iterator(cend());
+ }
+
+ //*********************************************************************
+ /// Returns a const reverse iterator to the end + 1 of the vector.
+ ///\return Const reverse iterator to the end + 1 of the vector.
+ //*********************************************************************
+ const_reverse_iterator crend() const
+ {
+ return const_reverse_iterator(cbegin());
+ }
+
+ //*********************************************************************
+ /// Resizes the vector.
+ /// If asserts or exceptions are enabled and the new size is larger than the
+ /// maximum then a vector_full is thrown.
+ ///\param new_size The new size.
+ //*********************************************************************
+ void resize(size_t new_size)
+ {
+ ETL_ASSERT(new_size <= MAX_SIZE, ETL_ERROR(vector_full));
+
+ // Choose the algorithm according to type.
+ // The unused branch should be optimised away.
+ if (is_simple_type<value_type>::value)
+ {
+ current_size = new_size;
+ }
+ else
+ {
+ // Size up or size down?
+ if (new_size > current_size)
+ {
+ while (current_size < new_size)
+ {
+ create_element();
+ }
+ }
+ else if (new_size < current_size)
+ {
+ while (current_size > new_size)
+ {
+ destroy_element();
+ }
+ }
+ }
+ }
+
+ //*********************************************************************
+ /// Resizes the vector.
+ /// If asserts or exceptions are enabled and the new size is larger than the
+ /// maximum then a vector_full is thrown.
+ ///\param new_size The new size.
+ ///\param value The value to fill new elements with. Default = default constructed value.
+ //*********************************************************************
+ void resize(size_t new_size, T value)
+ {
+ ETL_ASSERT(new_size <= MAX_SIZE, ETL_ERROR(vector_full));
+
+ // Choose the algorithm according to type.
+ // The unused branch should be optimised away.
+ if (is_simple_type<value_type>::value)
+ {
+ // Size up if necessary.
+ while (current_size < new_size)
+ {
+ p_buffer[current_size++] = value;
+ }
+
+ current_size = new_size;
+ }
+ else
+ {
+ // Size up?
+ if (new_size > current_size)
+ {
+ while (current_size < new_size)
+ {
+ create_element(value);
+ }
+ }
+ // Size down?
+ else if (new_size < current_size)
+ {
+ while (current_size > new_size)
+ {
+ destroy_element();
+ }
+ }
+ }
+ }
+
+ //*********************************************************************
+ /// Returns a reference to the value at index 'i'
+ ///\param i The index.
+ ///\return A reference to the value at index 'i'
+ //*********************************************************************
+ reference operator [](size_t i)
+ {
+ return p_buffer[i];
+ }
+
+ //*********************************************************************
+ /// Returns a const reference to the value at index 'i'
+ ///\param i The index.
+ ///\return A const reference to the value at index 'i'
+ //*********************************************************************
+ const_reference operator [](size_t i) const
+ {
+ return p_buffer[i];
+ }
+
+ //*********************************************************************
+ /// Returns a reference to the value at index 'i'
+ /// If asserts or exceptions are enabled, emits an etl::vector_out_of_bounds if the index is out of range.
+ ///\param i The index.
+ ///\return A reference to the value at index 'i'
+ //*********************************************************************
+ reference at(size_t i)
+ {
+ ETL_ASSERT(i < current_size, ETL_ERROR(vector_out_of_bounds));
+ return p_buffer[i];
+ }
+
+ //*********************************************************************
+ /// Returns a const reference to the value at index 'i'
+ /// If asserts or exceptions are enabled, emits an etl::vector_out_of_bounds if the index is out of range.
+ ///\param i The index.
+ ///\return A const reference to the value at index 'i'
+ //*********************************************************************
+ const_reference at(size_t i) const
+ {
+ ETL_ASSERT(i < current_size, ETL_ERROR(vector_out_of_bounds));
+ return p_buffer[i];
+ }
+
+ //*********************************************************************
+ /// Returns a reference to the first element.
+ ///\return A reference to the first element.
+ //*********************************************************************
+ reference front()
+ {
+ return p_buffer[0];
+ }
+
+ //*********************************************************************
+ /// Returns a const reference to the first element.
+ ///\return A const reference to the first element.
+ //*********************************************************************
+ const_reference front() const
+ {
+ return p_buffer[0];
+ }
+
+ //*********************************************************************
+ /// Returns a reference to the last element.
+ ///\return A reference to the last element.
+ //*********************************************************************
+ reference back()
+ {
+ return p_buffer[current_size - 1];
+ }
+
+ //*********************************************************************
+ /// Returns a const reference to the last element.
+ ///\return A const reference to the last element.
+ //*********************************************************************
+ const_reference back() const
+ {
+ return p_buffer[current_size - 1];
+ }
+
+ //*********************************************************************
+ /// Returns a pointer to the beginning of the vector data.
+ ///\return A pointer to the beginning of the vector data.
+ //*********************************************************************
+ pointer data()
+ {
+ return p_buffer;
+ }
+
+ //*********************************************************************
+ /// Returns a const pointer to the beginning of the vector data.
+ ///\return A const pointer to the beginning of the vector data.
+ //*********************************************************************
+ const_pointer data() const
+ {
+ return p_buffer;
+ }
+
+ //*********************************************************************
+ /// Assigns values to the vector.
+ /// If asserts or exceptions are enabled, emits vector_full if the vector does not have enough free space.
+ /// If asserts or exceptions are enabled, emits vector_iterator if the iterators are reversed.
+ ///\param first The iterator to the first element.
+ ///\param last The iterator to the last element + 1.
+ //*********************************************************************
+ template <typename TIterator>
+ void assign(TIterator first, TIterator last)
+ {
+#ifdef _DEBUG
+ difference_type count = std::distance(first, last);
+ ETL_ASSERT(static_cast<size_t>(count) <= MAX_SIZE, ETL_ERROR(vector_full));
+#endif
+
+ initialise();
+
+ // Choose the algorithm according to type.
+ // The unused branch should be optimised away.
+ if (is_simple_type<value_type>::value)
+ {
+ while (first != last)
+ {
+ p_buffer[current_size++] = *first++;
+ }
+ }
+ else
+ {
+ while (first != last)
+ {
+ create_element(*first);
+ ++first;
+ }
+ }
+ }
+
+ //*********************************************************************
+ /// Assigns values to the vector.
+ /// If asserts or exceptions are enabled, emits vector_full if the vector does not have enough free space.
+ ///\param n The number of elements to add.
+ ///\param value The value to insert for each element.
+ //*********************************************************************
+ void assign(size_t n, parameter_t value)
+ {
+ initialise();
+
+ ETL_ASSERT(n <= MAX_SIZE, ETL_ERROR(vector_full));
+
+ // Choose the algorithm according to type.
+ // The unused branch should be optimised away.
+ if (is_simple_type<value_type>::value)
+ {
+ while (n > 0)
+ {
+ p_buffer[current_size++] = value;
+ --n;
+ }
+ }
+ else
+ {
+ while (n > 0)
+ {
+ create_element(value);
+ --n;
+ }
+ }
+ }
+
+ //*************************************************************************
+ /// Clears the vector.
+ //*************************************************************************
+ void clear()
+ {
+ initialise();
+ }
+
+ //*************************************************************************
+ /// Increases the size of the vector by one, but does not initialise the new element.
+ /// If asserts or exceptions are enabled, throws a vector_full if the vector is already full.
+ //*************************************************************************
+ void push_back()
+ {
+#if defined(ETL_CHECK_PUSH_POP)
+ ETL_ASSERT(current_size != MAX_SIZE, ETL_ERROR(vector_full));
+#endif
+ create_element();
+ }
+
+ //*********************************************************************
+ /// Inserts a value at the end of the vector.
+ /// If asserts or exceptions are enabled, emits vector_full if the vector is already full.
+ ///\param value The value to add.
+ //*********************************************************************
+ void push_back(parameter_t value)
+ {
+#if defined(ETL_CHECK_PUSH_POP)
+ ETL_ASSERT(current_size != MAX_SIZE, ETL_ERROR(vector_full));
+#endif
+ create_element(value);
+ }
+
+ //*************************************************************************
+ /// Removes an element from the end of the vector.
+ /// Does nothing if the vector is empty.
+ //*************************************************************************
+ void pop_back()
+ {
+#if defined(ETL_CHECK_PUSH_POP)
+ ETL_ASSERT(current_size > 0, ETL_ERROR(vector_empty));
+#endif
+ destroy_element();
+ }
+
+ //*********************************************************************
+ /// Inserts a value to the vector.
+ /// If asserts or exceptions are enabled, emits vector_full if the vector is already full.
+ ///\param position The position to insert before.
+ ///\param value The value to insert.
+ //*********************************************************************
+ iterator insert(iterator position, parameter_t value)
+ {
+ ETL_ASSERT((current_size)+1 <= MAX_SIZE, ETL_ERROR(vector_full));
+
+ if (position != end())
+ {
+ create_element();
+ std::copy_backward(position, end() - 1, end());
+ *position = value;
+ }
+ else
+ {
+ create_element(value);
+ }
+
+ return position;
+ }
+
+ //*********************************************************************
+ /// Inserts 'n' values to the vector.
+ /// If asserts or exceptions are enabled, emits vector_full if the vector does not have enough free space.
+ ///\param position The position to insert before.
+ ///\param n The number of elements to add.
+ ///\param value The value to insert.
+ //*********************************************************************
+ void insert(iterator position, size_t n, parameter_t value)
+ {
+ ETL_ASSERT((current_size)+1 <= MAX_SIZE, ETL_ERROR(vector_full));
+
+ if (position == end())
+ {
+ while (n > 0)
+ {
+ create_element(value);
+ --n;
+ }
+ }
+ else
+ {
+ // Create copy (backwards).
+ size_t n_insert = n;
+ size_t from = size() - 1;
+ size_t to = from + n_insert;
+ size_t n_move = std::distance(position, end());
+ size_t n_create_copy = std::min(n_insert, n_move);
+
+ for (size_t i = 0; i < n_create_copy; ++i)
+ {
+ create_element_at(to--, p_buffer[from--]);
+ }
+
+ // Copy old.
+ size_t insert_index = std::distance(begin(), position);
+ from = insert_index;
+ to = from + n_insert;
+ size_t n_copy_old = (size() > n_insert) ? size() - n_insert : 0;
+ etl::copy_n(&p_buffer[from], n_copy_old, &p_buffer[to]);
+
+ // Copy new.
+ to = insert_index;
+
+ size_t n_create_new = (n_insert > n_create_copy) ? n_insert - n_create_copy : 0;
+ size_t n_copy_new = (n_insert > n_create_new) ? n_insert - n_create_new : 0;
+ std::fill_n(&p_buffer[to], n_copy_new, value);
+
+ // Create new.
+ to = size();
+
+ for (size_t i = 0; i < n_create_new; ++i)
+ {
+ create_element_at(to++, value);
+ }
+
+ current_size += n_insert;
+ }
+ }
+
+ //*********************************************************************
+ /// Inserts a range of values to the vector.
+ /// If asserts or exceptions are enabled, emits vector_full if the vector does not have enough free space.
+ /// For fundamental and pointer types.
+ ///\param position The position to insert before.
+ ///\param first The first element to add.
+ ///\param last The last + 1 element to add.
+ //*********************************************************************
+ template <class TIterator>
+ typename etl::enable_if<is_simple_type<typename std::iterator_traits<TIterator>::value_type>::value, void>::type
+ insert(iterator position, TIterator first, TIterator last)
+ {
+ size_t count = std::distance(first, last);
+
+ ETL_ASSERT((current_size)+count <= MAX_SIZE, ETL_ERROR(vector_full));
+
+ if (position == end())
+ {
+ while (first != last)
+ {
+ p_buffer[current_size++] = *first++;
+ }
+ }
+ else
+ {
+ size_t insert_index = std::distance(begin(), position);
+ size_t n_insert = count;
+
+ // Create copy (backwards).
+ size_t from = size() - 1;
+ size_t to = from + n_insert;
+ size_t n_move = std::distance(position, end());
+ size_t n_create_copy = std::min(n_insert, n_move);
+
+ for (size_t i = 0; i < n_create_copy; ++i)
+ {
+ p_buffer[to--] = p_buffer[from--];
+ }
+
+ // Copy old.
+ from = insert_index;
+ to = from + n_insert;
+ size_t n_copy_old = (size() > n_insert) ? size() - n_insert : 0;
+ etl::copy_n(&p_buffer[from], n_copy_old, &p_buffer[to]);
+
+ // Copy new.
+ to = insert_index;
+ size_t n_create_new = (n_insert > n_create_copy) ? n_insert - n_create_copy : 0;
+ size_t n_copy_new = (n_insert > n_create_new) ? n_insert - n_create_new : 0;
+ etl::copy_n(first, n_copy_new, &p_buffer[to]);
+ first += n_copy_new;
+
+ // Create new.
+ to = size();
+ for (size_t i = 0; i < n_create_new; ++i)
+ {
+ p_buffer[to++] = *first++;
+ }
+
+ current_size += n_insert;
+ }
+ }
+
+ //*********************************************************************
+ /// Inserts a range of values to the vector.
+ /// If asserts or exceptions are enabled, emits vector_full if the vector does not have enough free space.
+ /// For non-fundamental types.
+ ///\param position The position to insert before.
+ ///\param first The first element to add.
+ ///\param last The last + 1 element to add.
+ //*********************************************************************
+ template <class TIterator>
+ typename etl::enable_if<!is_simple_type<typename std::iterator_traits<TIterator>::value_type>::value, void>::type
+ insert(iterator position, TIterator first, TIterator last)
+ {
+ size_t count = std::distance(first, last);
+
+ ETL_ASSERT((current_size)+count <= MAX_SIZE, ETL_ERROR(vector_full));
+
+ if (position == end())
+ {
+ while (first != last)
+ {
+ create_element(*first);
+ ++first;
+ }
+ }
+ else
+ {
+ size_t insert_index = std::distance(begin(), position);
+ size_t n_insert = count;
+
+ // Create copy (backwards).
+ size_t from = size() - 1;
+ size_t to = from + n_insert;
+ size_t n_move = std::distance(position, end());
+ size_t n_create_copy = std::min(n_insert, n_move);
+ for (size_t i = 0; i < n_create_copy; ++i)
+ {
+ create_element_at(to--, p_buffer[from--]);
+ }
+
+ // Copy old.
+ from = insert_index;
+ to = from + n_insert;
+ size_t n_copy_old = (size() > n_insert) ? size() - n_insert : 0;
+ etl::copy_n(&p_buffer[from], n_copy_old, &p_buffer[to]);
+
+ // Copy new.
+ to = insert_index;
+ size_t n_create_new = (n_insert > n_create_copy) ? n_insert - n_create_copy : 0;
+ size_t n_copy_new = (n_insert > n_create_new) ? n_insert - n_create_new : 0;
+ etl::copy_n(first, n_copy_new, &p_buffer[to]);
+ first += n_copy_new;
+
+ // Create new.
+ to = size();
+ for (size_t i = 0; i < n_create_new; ++i)
+ {
+ create_element_at(to++, *first);
+ ++first;
+ }
+
+ current_size += n_insert;
+ }
+ }
+
+ //*********************************************************************
+ /// Erases an element.
+ ///\param i_element Iterator to the element.
+ ///\return An iterator pointing to the element that followed the erased element.
+ //*********************************************************************
+ iterator erase(iterator i_element)
+ {
+ std::copy(i_element + 1, end(), i_element);
+ destroy_element();
+
+ return i_element;
+ }
+
+ //*********************************************************************
+ /// Erases a range of elements.
+ /// The range includes all the elements between first and last, including the
+ /// element pointed by first, but not the one pointed by last.
+ ///\param first Iterator to the first element.
+ ///\param last Iterator to the last element.
+ ///\return An iterator pointing to the element that followed the erased element.
+ //*********************************************************************
+ iterator erase(iterator first, iterator last)
+ {
+ std::copy(last, end(), first);
+ size_t n_delete = std::distance(first, last);
+
+ if (is_simple_type<value_type>::value)
+ {
+ // Just adjust the count.
+ current_size -= n_delete;
+ }
+ else
+ {
+ // Destroy the elements left over at the end.
+ while (n_delete-- > 0)
+ {
+ destroy_element();
+ }
+ }
+
+ return first;
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ ivector& operator = (const ivector& rhs)
+ {
+ if (&rhs != this)
+ {
+ assign(rhs.cbegin(), rhs.cend());
+ }
+
+ return *this;
+ }
+
+ protected:
+
+ //*********************************************************************
+ /// Constructor.
+ //*********************************************************************
+ ivector(T* p_buffer, size_t MAX_SIZE)
+ : vector_base(MAX_SIZE),
+ p_buffer(p_buffer)
+ {
+ }
+
+ //*********************************************************************
+ /// Initialise the vector.
+ //*********************************************************************
+ void initialise()
+ {
+ // Choose the algorithm according to type.
+ // The unused branch should be optimised away.
+ if (is_simple_type<value_type>::value)
+ {
+ current_size = 0;
+ }
+ else
+ {
+ while (current_size > 0)
+ {
+ destroy_element();
+ }
+ }
+ }
+
+ T* p_buffer;
+
+ private:
+
+ //*********************************************************************
+ /// Create a new element with a default value at the back.
+ //*********************************************************************
+ inline void create_element()
+ {
+ new(&p_buffer[current_size++]) T();
+ }
+
+ //*********************************************************************
+ /// Create a new element with a value at the back
+ //*********************************************************************
+ inline void create_element(parameter_t value)
+ {
+ new(&p_buffer[current_size++]) T(value);
+ }
+
+ //*********************************************************************
+ /// Create a new element with a value at the index
+ //*********************************************************************
+ inline void create_element_at(size_t index, parameter_t value)
+ {
+ new(&p_buffer[index]) T(value);
+ }
+
+ //*********************************************************************
+ /// Destroy an element at the back.
+ //*********************************************************************
+ inline void destroy_element()
+ {
+ p_buffer[--current_size].~T();
+ }
+
+ // Disable copy construction.
+ ivector(const ivector&);
+ };
+
+ //***************************************************************************
+ /// Equal operator.
+ ///\param lhs Reference to the first vector.
+ ///\param rhs Reference to the second vector.
+ ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
+ ///\ingroup vector
+ //***************************************************************************
+ template <typename T>
+ bool operator ==(const etl::ivector<T>& lhs, const etl::ivector<T>& rhs)
+ {
+ return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin());
+ }
+
+ //***************************************************************************
+ /// Not equal operator.
+ ///\param lhs Reference to the first vector.
+ ///\param rhs Reference to the second vector.
+ ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
+ ///\ingroup vector
+ //***************************************************************************
+ template <typename T>
+ bool operator !=(const etl::ivector<T>& lhs, const etl::ivector<T>& rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+ //***************************************************************************
+ /// Less than operator.
+ ///\param lhs Reference to the first vector.
+ ///\param rhs Reference to the second vector.
+ ///\return <b>true</b> if the first vector is lexicographically less than the second, otherwise <b>false</b>
+ ///\ingroup vector
+ //***************************************************************************
+ template <typename T>
+ bool operator <(const etl::ivector<T>& lhs, const etl::ivector<T>& rhs)
+ {
+ return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
+ }
+
+ //***************************************************************************
+ /// Greater than operator.
+ ///\param lhs Reference to the first vector.
+ ///\param rhs Reference to the second vector.
+ ///\return <b>true</b> if the first vector is lexicographically greater than the second, otherwise <b>false</b>
+ ///\ingroup vector
+ //***************************************************************************
+ template <typename T>
+ bool operator >(const etl::ivector<T>& lhs, const etl::ivector<T>& rhs)
+ {
+ return (rhs < lhs);
+ }
+
+ //***************************************************************************
+ /// Less than or equal operator.
+ ///\param lhs Reference to the first vector.
+ ///\param rhs Reference to the second vector.
+ ///\return <b>true</b> if the first vector is lexicographically less than or equal to the second, otherwise <b>false</b>
+ ///\ingroup vector
+ //***************************************************************************
+ template <typename T>
+ bool operator <=(const etl::ivector<T>& lhs, const etl::ivector<T>& rhs)
+ {
+ return !(lhs > rhs);
+ }
+
+ //***************************************************************************
+ /// Greater than or equal operator.
+ ///\param lhs Reference to the first vector.
+ ///\param rhs Reference to the second vector.
+ ///\return <b>true</b> if the first vector is lexicographically greater than or equal to the second, otherwise <b>false</b>
+ ///\ingroup vector
+ //***************************************************************************
+ template <typename T>
+ bool operator >=(const etl::ivector<T>& lhs, const etl::ivector<T>& rhs)
+ {
+ return !(lhs < rhs);
+ }
+}
+
+#include "private/ivectorpointer.h"
+
+#undef __ETL_IN_IVECTOR_H__
+#endif
diff --git a/lib/etl/jenkins.h b/lib/etl/jenkins.h
new file mode 100644
index 0000000..7dace16
--- /dev/null
+++ b/lib/etl/jenkins.h
@@ -0,0 +1,168 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_JENKINS__
+#define __ETL_JENKINS__
+
+#include <stdint.h>
+#include <iterator>
+
+#include "platform.h"
+#include "static_assert.h"
+#include "type_traits.h"
+#include "error_handler.h"
+#include "ihash.h"
+
+#if defined(ETL_COMPILER_KEIL)
+#pragma diag_suppress 1300
+#endif
+
+///\defgroup jenkins Jenkins 32 & 64 bit hash calculations
+///\ingroup maths
+
+namespace etl
+{
+ //***************************************************************************
+ /// Calculates the jenkins hash.
+ ///\ingroup jenkins
+ //***************************************************************************
+ template <typename THash>
+ class jenkins
+ {
+ public:
+
+ STATIC_ASSERT((etl::is_same<THash, uint32_t>::value || etl::is_same<THash, uint64_t>::value), "Only 32 & 64 bit types supported");
+
+ typedef THash value_type;
+
+ //*************************************************************************
+ /// Default constructor.
+ //*************************************************************************
+ jenkins()
+ {
+ reset();
+ }
+
+ //*************************************************************************
+ /// Constructor from range.
+ /// \param begin Start of the range.
+ /// \param end End of the range.
+ //*************************************************************************
+ template<typename TIterator>
+ jenkins(TIterator begin, const TIterator end)
+ {
+ STATIC_ASSERT(sizeof(typename std::iterator_traits<TIterator>::value_type) == 1, "Incompatible type");
+
+ reset();
+
+ while (begin != end)
+ {
+ hash += *begin++;
+ hash += (hash << 10);
+ hash ^= (hash >> 6);
+ }
+ }
+
+ //*************************************************************************
+ /// Resets the CRC to the initial state.
+ //*************************************************************************
+ void reset()
+ {
+ hash = 0;
+ is_finalised = false;
+ }
+
+ //*************************************************************************
+ /// Adds a range.
+ /// \param begin
+ /// \param end
+ //*************************************************************************
+ template<typename TIterator>
+ void add(TIterator begin, const TIterator end)
+ {
+ STATIC_ASSERT(sizeof(typename std::iterator_traits<TIterator>::value_type) == 1, "Incompatible type");
+ ETL_ASSERT(!is_finalised, ETL_ERROR(hash_finalised));
+
+ while (begin != end)
+ {
+ hash += *begin++;
+ hash += (hash << 10);
+ hash ^= (hash >> 6);
+ }
+ }
+
+ //*************************************************************************
+ /// \param value The char to add to the jenkins.
+ //*************************************************************************
+ void add(uint8_t value)
+ {
+ ETL_ASSERT(!is_finalised, ETL_ERROR(hash_finalised));
+
+ hash += value;
+ hash += (hash << 10);
+ hash ^= (hash >> 6);
+ }
+
+ //*************************************************************************
+ /// Gets the jenkins value.
+ //*************************************************************************
+ value_type value()
+ {
+ finalise();
+ return hash;
+ }
+
+ //*************************************************************************
+ /// Conversion operator to value_type.
+ //*************************************************************************
+ operator value_type ()
+ {
+ return value();
+ }
+
+ private:
+
+ void finalise()
+ {
+ if (!is_finalised)
+ {
+ hash += (hash << 3);
+ hash ^= (hash >> 11);
+ hash += (hash << 15);
+ is_finalised = true;
+ }
+ }
+
+ value_type hash;
+ bool is_finalised;
+ };
+}
+
+#endif
diff --git a/lib/etl/largest.h b/lib/etl/largest.h
new file mode 100644
index 0000000..9eae7ab
--- /dev/null
+++ b/lib/etl/largest.h
@@ -0,0 +1,168 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_LARGEST__
+#define __ETL_LARGEST__
+
+///\defgroup largest largest
+///\ingroup utilities
+
+#include "type_traits.h"
+
+namespace etl
+{
+ //***************************************************************************
+ /// Template to determine the largest type and size.
+ /// Supports up to 16 types.
+ /// Defines 'value_type' which is the type of the largest parameter.
+ /// Defines 'size' which is the size of the largest parameter.
+ ///\ingroup largest
+ //***************************************************************************
+ template <typename T1, typename T2 = void, typename T3 = void, typename T4 = void,
+ typename T5 = void, typename T6 = void, typename T7 = void, typename T8 = void,
+ typename T9 = void, typename T10 = void, typename T11 = void, typename T12 = void,
+ typename T13 = void, typename T14 = void, typename T15 = void, typename T16 = void>
+ struct largest_type
+ {
+ private:
+
+ // Declaration.
+ template <const bool Boolean, typename TrueType, typename FalseType>
+ struct choose_type;
+
+ // Specialisation for 'true'.
+ // Defines 'type' as 'TrueType'.
+ template <typename TrueType, typename FalseType>
+ struct choose_type<true, TrueType, FalseType>
+ {
+ typedef TrueType type;
+ };
+
+ // Specialisation for 'false'.
+ // Defines 'type' as 'FalseType'.
+ template <typename TrueType, typename FalseType>
+ struct choose_type<false, TrueType, FalseType>
+ {
+ typedef FalseType type;
+ };
+
+ public:
+
+ // Define 'largest_other' as 'largest_type' with all but the first parameter.
+ typedef typename largest_type<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::type largest_other;
+
+ // Set 'type' to be the largest of the first parameter and any of the others.
+ // This is recursive.
+ typedef typename choose_type<(sizeof(T1) > sizeof(largest_other)), // Boolean
+ T1, // TrueType
+ largest_other> // FalseType
+ ::type type; // The largest type of the two.
+
+ // The size of the largest type.
+ enum
+ {
+ size = sizeof(type)
+ };
+ };
+
+ //***************************************************************************
+ // Specialisation for one template parameter.
+ //***************************************************************************
+ template <typename T1>
+ struct largest_type<T1, void, void, void,
+ void, void, void, void,
+ void, void, void, void,
+ void, void, void, void>
+ {
+ typedef T1 type;
+
+ enum
+ {
+ size = sizeof(type)
+ };
+ };
+
+ //***************************************************************************
+ /// Template to determine the largest alignment.
+ /// Supports up to 16 types.
+ /// Defines <b>value</b> which is the largest alignment of all the parameters.
+ ///\ingroup largest
+ //***************************************************************************
+ template <typename T1, typename T2 = void, typename T3 = void, typename T4 = void,
+ typename T5 = void, typename T6 = void, typename T7 = void, typename T8 = void,
+ typename T9 = void, typename T10 = void, typename T11 = void, typename T12 = void,
+ typename T13 = void, typename T14 = void, typename T15 = void, typename T16 = void>
+ struct largest_alignment
+ {
+ // Determine the largest size.
+ template <const size_t size1, const size_t size2>
+ struct max_size
+ {
+ enum
+ {
+ value = (size1 > size2) ? size1 : size2
+ };
+ };
+
+ // All of the alignments.
+ enum
+ {
+ t1 = alignment_of<T1>::value,
+ t2 = alignment_of<T2>::value,
+ t3 = alignment_of<T3>::value,
+ t4 = alignment_of<T4>::value,
+ t5 = alignment_of<T5>::value,
+ t6 = alignment_of<T6>::value,
+ t7 = alignment_of<T7>::value,
+ t8 = alignment_of<T8>::value,
+ t9 = alignment_of<T9>::value,
+ t10 = alignment_of<T10>::value,
+ t11 = alignment_of<T11>::value,
+ t12 = alignment_of<T12>::value,
+ t13 = alignment_of<T13>::value,
+ t14 = alignment_of<T14>::value,
+ t15 = alignment_of<T15>::value,
+ t16 = alignment_of<T16>::value
+ };
+
+ public:
+
+ // The largest of all of them.
+ enum
+ {
+ value = max_size<t1, max_size<t2, max_size<t3, max_size<t4, max_size<t5, max_size<t6, max_size<t7, max_size<t8,
+ max_size<t9, max_size<t10, max_size<t11, max_size<t12, max_size<t13, max_size<t14, max_size<t15, t16>
+ ::value>::value>::value>::value>::value>::value>::value>::value>
+ ::value>::value>::value>::value>::value>::value>::value
+ };
+ };
+}
+
+#endif
diff --git a/lib/etl/list.h b/lib/etl/list.h
new file mode 100644
index 0000000..361d1a8
--- /dev/null
+++ b/lib/etl/list.h
@@ -0,0 +1,137 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_LIST__
+#define __ETL_LIST__
+
+#include <stddef.h>
+
+#include "ilist.h"
+#include "container.h"
+#include "pool.h"
+
+//*****************************************************************************
+///\defgroup list list
+/// A linked list with the capacity defined at compile time.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+ //*************************************************************************
+ /// A templated list implementation that uses a fixed size buffer.
+ ///\note 'merge' and 'splice' and are not supported.
+ //*************************************************************************
+ template <typename T, const size_t MAX_SIZE_>
+ class list : public ilist<T>
+ {
+ public:
+
+ static const size_t MAX_SIZE = MAX_SIZE_;
+
+ public:
+
+ typedef T value_type;
+ typedef T* pointer;
+ typedef const T* const_pointer;
+ typedef T& reference;
+ typedef const T& const_reference;
+ typedef size_t size_type;
+
+ //*************************************************************************
+ /// Default constructor.
+ //*************************************************************************
+ list()
+ : ilist<T>(node_pool, MAX_SIZE)
+ {
+ ilist<T>::initialise();
+ }
+
+ //*************************************************************************
+ /// Construct from size.
+ //*************************************************************************
+ explicit list(size_t initial_size)
+ : ilist<T>(node_pool, MAX_SIZE)
+ {
+ ilist<T>::assign(initial_size, T());
+ }
+
+ //*************************************************************************
+ /// Construct from size and value.
+ //*************************************************************************
+ list(size_t initial_size, typename ilist<T>::parameter_t value)
+ : ilist<T>(node_pool, MAX_SIZE)
+ {
+ ilist<T>::assign(initial_size, value);
+ }
+
+ //*************************************************************************
+ /// Copy constructor.
+ //*************************************************************************
+ list(const list& other)
+ : ilist<T>(node_pool, MAX_SIZE)
+ {
+ if (this != &other)
+ {
+ ilist<T>::assign(other.cbegin(), other.cend());
+ }
+ }
+
+ //*************************************************************************
+ /// Construct from range.
+ //*************************************************************************
+ template <typename TIterator>
+ list(TIterator first, TIterator last)
+ : ilist<T>(node_pool, MAX_SIZE)
+ {
+ ilist<T>::assign(first, last);
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ list& operator = (const list& rhs)
+ {
+ if (&rhs != this)
+ {
+ ilist<T>::assign(rhs.cbegin(), rhs.cend());
+ }
+
+ return *this;
+ }
+
+ private:
+
+ /// The pool of nodes used in the list.
+ etl::pool<typename list::data_node_t, MAX_SIZE> node_pool;
+ };
+}
+
+#endif
diff --git a/lib/etl/log.h b/lib/etl/log.h
new file mode 100644
index 0000000..26d9b5f
--- /dev/null
+++ b/lib/etl/log.h
@@ -0,0 +1,113 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_LOG__
+#define __ETL_LOG__
+
+#include <stddef.h>
+
+///\defgroup log log
+/// log<N, BASE> : Calculates logs to any base, rounded down to the nearest integer.<br>
+/// log2<N> : Calculates logs to base 2, rounded down to the nearest integer.<br>
+/// log10<N> : Calculates logs to base 10, rounded down to the nearest integer.<br>
+///\ingroup maths
+
+namespace etl
+{
+ //***************************************************************************
+ ///\ingroup log
+ /// The base generic log template.
+ /// Defines <b>value</b> as the log of the number at the specified base.
+ /// The result is rounded down to the next integer.
+ ///\tparam NV The number to find the log of.
+ ///\tparam BASE The base of the log.
+ //***************************************************************************
+ template <const size_t NV, const size_t BASE>
+ struct log
+ {
+ enum value_type
+ {
+ // Recursive definition.
+ value = (NV >= BASE) ? 1 + log<NV / BASE, BASE>::value : 0
+ };
+ };
+
+ //***************************************************************************
+ // Specialisation for N = 1
+ //***************************************************************************
+ template <const size_t BASE>
+ struct log<1, BASE>
+ {
+ enum value_type
+ {
+ value = 0
+ };
+ };
+
+ //***************************************************************************
+ // Specialisation for N = 0
+ //***************************************************************************
+ template <const size_t BASE>
+ struct log<0, BASE>
+ {
+ enum value_type
+ {
+ value = 0
+ };
+ };
+
+ //***************************************************************************
+ ///\ingroup log
+ /// Calculates base 2 logs.
+ //***************************************************************************
+ template <const size_t NV>
+ struct log2
+ {
+ enum value_type
+ {
+ value = log<NV, 2>::value
+ };
+ };
+
+ //***************************************************************************
+ ///\ingroup log
+ /// Calculates base 10 logs.
+ //***************************************************************************
+ template <const size_t NV>
+ struct log10
+ {
+ enum value_type
+ {
+ value = log<NV, 10>::value
+ };
+ };
+}
+
+#endif
diff --git a/lib/etl/map.h b/lib/etl/map.h
new file mode 100644
index 0000000..9ec0c71
--- /dev/null
+++ b/lib/etl/map.h
@@ -0,0 +1,113 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove, rlindeman
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_MAP__
+#define __ETL_MAP__
+
+#include <stddef.h>
+#include <iterator>
+#include <functional>
+
+#include "imap.h"
+#include "container.h"
+#include "pool.h"
+
+//*****************************************************************************
+///\defgroup map map
+/// A map with the capacity defined at compile time.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+ //*************************************************************************
+ /// A templated map implementation that uses a fixed size buffer.
+ //*************************************************************************
+ template <typename TKey, typename TValue, const size_t MAX_SIZE_, typename TCompare = std::less<TKey> >
+ class map : public imap<TKey, TValue, TCompare>
+ {
+ public:
+
+ static const size_t MAX_SIZE = MAX_SIZE_;
+
+ //*************************************************************************
+ /// Default constructor.
+ //*************************************************************************
+ map()
+ : imap<TKey, TValue, TCompare>(node_pool, MAX_SIZE)
+ {
+ imap<TKey, TValue, TCompare>::initialise();
+ }
+
+ //*************************************************************************
+ /// Copy constructor.
+ //*************************************************************************
+ map(const map& other)
+ : imap<TKey, TValue, TCompare>(node_pool, MAX_SIZE)
+ {
+ imap<TKey, TValue, TCompare>::assign(other.cbegin(), other.cend());
+ }
+
+ //*************************************************************************
+ /// Constructor, from an iterator range.
+ ///\tparam TIterator The iterator type.
+ ///\param first The iterator to the first element.
+ ///\param last The iterator to the last element + 1.
+ //*************************************************************************
+ template <typename TIterator>
+ map(TIterator first, TIterator last)
+ : imap<TKey, TValue, TCompare>(node_pool, MAX_SIZE)
+ {
+ imap<TKey, TValue, TCompare>::assign(first, last);
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ map& operator = (const map& rhs)
+ {
+ // Skip if doing self assignment
+ if (this != &rhs)
+ {
+ imap<TKey, TValue, TCompare>::assign(rhs.cbegin(), rhs.cend());
+ }
+
+ return *this;
+ }
+
+ private:
+
+ /// The pool of data nodes used for the map.
+ pool<typename imap<TKey, TValue, TCompare>::Data_Node, MAX_SIZE> node_pool;
+ };
+
+}
+
+#endif
diff --git a/lib/etl/multimap.h b/lib/etl/multimap.h
new file mode 100644
index 0000000..06658b4
--- /dev/null
+++ b/lib/etl/multimap.h
@@ -0,0 +1,112 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove, rlindeman
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_MULTIMAP__
+#define __ETL_MULTIMAP__
+
+#include <stddef.h>
+#include <iterator>
+#include <functional>
+
+#include "imultimap.h"
+#include "container.h"
+#include "pool.h"
+
+//*****************************************************************************
+/// A multimap with the capacity defined at compile time.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+ //*************************************************************************
+ /// A templated multimap implementation that uses a fixed size buffer.
+ //*************************************************************************
+ template <typename TKey, typename TValue, const size_t MAX_SIZE_, typename TCompare = std::less<TKey> >
+ class multimap : public imultimap<TKey, TValue, TCompare>
+ {
+ public:
+
+ static const size_t MAX_SIZE = MAX_SIZE_;
+
+ //*************************************************************************
+ /// Default constructor.
+ //*************************************************************************
+ multimap()
+ : imultimap<TKey, TValue, TCompare>(node_pool, MAX_SIZE)
+ {
+ imultimap<TKey, TValue, TCompare>::initialise();
+ }
+
+ //*************************************************************************
+ /// Copy constructor.
+ //*************************************************************************
+ explicit multimap(const multimap& other)
+ : imultimap<TKey, TValue, TCompare>(node_pool, MAX_SIZE)
+ {
+ imultimap<TKey, TValue, TCompare>::assign(other.cbegin(), other.cend());
+ }
+
+ //*************************************************************************
+ /// Constructor, from an iterator range.
+ ///\tparam TIterator The iterator type.
+ ///\param first The iterator to the first element.
+ ///\param last The iterator to the last element + 1.
+ //*************************************************************************
+ template <typename TIterator>
+ multimap(TIterator first, TIterator last)
+ : imultimap<TKey, TValue, TCompare>(node_pool, MAX_SIZE)
+ {
+ imultimap<TKey, TValue, TCompare>::assign(first, last);
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ multimap& operator = (const multimap& rhs)
+ {
+ // Skip if doing self assignment
+ if (this != &rhs)
+ {
+ imultimap<TKey, TValue, TCompare>::assign(rhs.cbegin(), rhs.cend());
+ }
+
+ return *this;
+ }
+
+ private:
+
+ /// The pool of data nodes used for the multimap.
+ pool<typename imultimap<TKey, TValue, TCompare>::Data_Node, MAX_SIZE> node_pool;
+ };
+
+}
+
+#endif
diff --git a/lib/etl/multiset.h b/lib/etl/multiset.h
new file mode 100644
index 0000000..0668f9a
--- /dev/null
+++ b/lib/etl/multiset.h
@@ -0,0 +1,112 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove, rlindeman
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_MULTISET__
+#define __ETL_MULTISET__
+
+#include <stddef.h>
+#include <iterator>
+#include <functional>
+
+#include "imultiset.h"
+#include "container.h"
+#include "pool.h"
+
+//*****************************************************************************
+/// A multiset with the capacity defined at compile time.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+ //*************************************************************************
+ /// A templated multiset implementation that uses a fixed size buffer.
+ //*************************************************************************
+ template <typename T, const size_t MAX_SIZE_, typename TCompare = std::less<T> >
+ class multiset : public imultiset<T, TCompare>
+ {
+ public:
+
+ static const size_t MAX_SIZE = MAX_SIZE_;
+
+ //*************************************************************************
+ /// Default constructor.
+ //*************************************************************************
+ multiset()
+ : imultiset<T, TCompare>(node_pool, MAX_SIZE)
+ {
+ imultiset<T, TCompare>::initialise();
+ }
+
+ //*************************************************************************
+ /// Copy constructor.
+ //*************************************************************************
+ explicit multiset(const multiset& other)
+ : imultiset<T, TCompare>(node_pool, MAX_SIZE)
+ {
+ imultiset<T, TCompare>::assign(other.cbegin(), other.cend());
+ }
+
+ //*************************************************************************
+ /// Constructor, from an iterator range.
+ ///\tparam TIterator The iterator type.
+ ///\param first The iterator to the first element.
+ ///\param last The iterator to the last element + 1.
+ //*************************************************************************
+ template <typename TIterator>
+ multiset(TIterator first, TIterator last)
+ : imultiset<T, TCompare>(node_pool, MAX_SIZE)
+ {
+ imultiset<T, TCompare>::assign(first, last);
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ multiset& operator = (const multiset& rhs)
+ {
+ // Skip if doing self assignment
+ if (this != &rhs)
+ {
+ imultiset<T, TCompare>::assign(rhs.cbegin(), rhs.cend());
+ }
+
+ return *this;
+ }
+
+ private:
+
+ /// The pool of data nodes used for the multiset.
+ pool<typename imultiset<T, TCompare>::Data_Node, MAX_SIZE> node_pool;
+ };
+
+}
+
+#endif
diff --git a/lib/etl/murmur3.h b/lib/etl/murmur3.h
new file mode 100644
index 0000000..8300c25
--- /dev/null
+++ b/lib/etl/murmur3.h
@@ -0,0 +1,235 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_MURMUR3__
+#define __ETL_MURMUR3__
+
+#include <stdint.h>
+
+#include "platform.h"
+#include "ihash.h"
+#include "binary.h"
+#include "error_handler.h"
+
+#if defined(ETL_COMPILER_KEIL)
+#pragma diag_suppress 1300
+#endif
+
+///\defgroup murmur3 Murmur3 hash calculations
+///\ingroup maths
+
+namespace etl
+{
+ //***************************************************************************
+ /// Calculates the murmur3 hash.
+ /// See https://en.wikipedia.org/wiki/MurmurHash for more details.
+ ///\ingroup murmur3
+ //***************************************************************************
+ template <typename THash>
+ class murmur3
+ {
+ public:
+
+ STATIC_ASSERT((etl::is_same<THash, uint32_t>::value || etl::is_same<THash, uint64_t>::value), "Only 32 & 64 bit types supported");
+
+ typedef THash value_type;
+
+ //*************************************************************************
+ /// Default constructor.
+ /// \param seed The seed value. Default = 0.
+ //*************************************************************************
+ murmur3(value_type seed = 0)
+ : seed(seed)
+ {
+ reset();
+ }
+
+ //*************************************************************************
+ /// Constructor from range.
+ /// \param begin Start of the range.
+ /// \param end End of the range.
+ /// \param seed The seed value. Default = 0.
+ //*************************************************************************
+ template<typename TIterator>
+ murmur3(TIterator begin, const TIterator end, value_type seed = 0)
+ : seed(seed)
+ {
+ STATIC_ASSERT(sizeof(typename std::iterator_traits<TIterator>::value_type) == 1, "Incompatible type");
+
+ reset();
+ while (begin != end)
+ {
+ block |= (*begin++) << (block_fill_count * 8);
+
+ if (++block_fill_count == FULL_BLOCK)
+ {
+ add_block();
+ block_fill_count = 0;
+ block = 0;
+ }
+
+ ++char_count;
+ }
+ }
+
+ //*************************************************************************
+ /// Resets the hash to the initial state.
+ //*************************************************************************
+ void reset()
+ {
+ hash = seed;
+ char_count = 0;
+ block = 0;
+ block_fill_count = 0;
+ is_finalised = false;
+ }
+
+ //*************************************************************************
+ /// Adds a range.
+ /// \param begin
+ /// \param end
+ //*************************************************************************
+ template<typename TIterator>
+ void add(TIterator begin, const TIterator end)
+ {
+ STATIC_ASSERT(sizeof(typename std::iterator_traits<TIterator>::value_type) == 1, "Incompatible type");
+ ETL_ASSERT(!is_finalised, ETL_ERROR(hash_finalised));
+
+ while (begin != end)
+ {
+ block |= (*begin++) << (block_fill_count * 8);
+
+ if (++block_fill_count == FULL_BLOCK)
+ {
+ add_block();
+ block_fill_count = 0;
+ block = 0;
+ }
+
+ ++char_count;
+ }
+ }
+
+ //*************************************************************************
+ /// Adds a uint8_t value.
+ /// If the hash has already been finalised then a 'hash_finalised' error will be emitted.
+ /// \param value The char to add to the hash.
+ //*************************************************************************
+ void add(uint8_t value)
+ {
+ // We can't add to a finalised hash!
+ ETL_ASSERT(!is_finalised, ETL_ERROR(hash_finalised));
+
+ block |= value << (block_fill_count * 8);
+
+ if (++block_fill_count == FULL_BLOCK)
+ {
+ add_block();
+ block_fill_count = 0;
+ block = 0;
+ }
+
+ ++char_count;
+ }
+
+ //*************************************************************************
+ /// Gets the hash value.
+ //*************************************************************************
+ value_type value()
+ {
+ finalise();
+ return hash;
+ }
+
+ //*************************************************************************
+ /// Conversion operator to value_type.
+ //*************************************************************************
+ operator value_type ()
+ {
+ return value();
+ }
+
+ private:
+
+ //*************************************************************************
+ /// Adds a filled block to the hash.
+ //*************************************************************************
+ void add_block()
+ {
+ block *= CONSTANT1;
+ block = rotate_left(block, SHIFT1);
+ block *= CONSTANT2;
+
+ hash ^= block;
+ hash = rotate_left(hash, SHIFT2);
+ hash = (hash * MULTIPLY) + ADD;
+ }
+
+ //*************************************************************************
+ /// Finalises the hash.
+ //*************************************************************************
+ void finalise()
+ {
+ if (!is_finalised)
+ {
+ block *= CONSTANT1;
+ block = rotate_left(block, SHIFT1);
+ block *= CONSTANT2;
+
+ hash ^= block;
+ hash ^= char_count;
+ hash ^= (hash >> 16);
+ hash *= 0x85EBCA6B;
+ hash ^= (hash >> 13);
+ hash *= 0xC2B2AE35;
+ hash ^= (hash >> 16);
+
+ is_finalised = true;
+ }
+ }
+
+ bool is_finalised;
+ uint8_t block_fill_count;
+ size_t char_count;
+ value_type block;
+ value_type hash;
+ value_type seed;
+
+ static const uint8_t FULL_BLOCK = 4;
+ static const value_type CONSTANT1 = 0xCC9E2D51;
+ static const value_type CONSTANT2 = 0x1B873593;
+ static const value_type SHIFT1 = 15;
+ static const value_type SHIFT2 = 13;
+ static const value_type MULTIPLY = 5;
+ static const value_type ADD = 0xE6546B64;
+ };
+}
+
+#endif
diff --git a/lib/etl/nullptr.h b/lib/etl/nullptr.h
new file mode 100644
index 0000000..84979c7
--- /dev/null
+++ b/lib/etl/nullptr.h
@@ -0,0 +1,116 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_NULLPTR__
+#define __ETL_NULLPTR__
+
+#include "platform.h"
+
+///\defgroup nullptr nullptr
+/// A definition of nullptr for compilers that don't support it as standard.
+///\ingroup utilities
+
+#if defined(NO_NULLPTR_SUPPORT)
+namespace std
+{
+ //*****************************************************************************
+ /// A null pointer type.
+ ///\ingroup nullptr
+ //*****************************************************************************
+ class nullptr_t
+ {
+ public:
+
+ // Convertible to any type of null non-member pointer.
+ template<typename T>
+ operator T*() const
+ {
+ return 0;
+ }
+
+ // Or any type of null member pointer.
+ template<typename ANYCLASS, typename T>
+ operator T ANYCLASS::*() const
+ {
+ return 0;
+ }
+
+ private:
+
+ // Can't take address of nullptr.
+ void operator&() const;
+ };
+
+ //*****************************************************************************
+ /// A null pointer.
+ ///\ingroup nullptr
+ //*****************************************************************************
+ const nullptr_t nullptr = {};
+}
+
+//*****************************************************************************
+/// A null pointer type.
+///\ingroup nullptr
+//*****************************************************************************
+class nullptr_t
+{
+public:
+
+ // Convertible to any type of null non-member pointer.
+ template<typename T>
+ operator T*() const
+ {
+ return 0;
+ }
+
+ // Or any type of null member pointer.
+ template<typename ANYCLASS, typename T>
+ operator T ANYCLASS::*() const
+ {
+ return 0;
+ }
+
+private:
+
+ // Can't take address of nullptr.
+ void operator&() const;
+};
+
+//*****************************************************************************
+/// A null pointer.
+///\ingroup nullptr
+//*****************************************************************************
+const nullptr_t nullptr = {};
+
+#else
+ #include <cstddef>
+#endif
+#endif
+
diff --git a/lib/etl/numeric.h b/lib/etl/numeric.h
new file mode 100644
index 0000000..064bab6
--- /dev/null
+++ b/lib/etl/numeric.h
@@ -0,0 +1,58 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_NUMERIC__
+#define __ETL_NUMERIC__
+
+///\defgroup numeric numeric
+///\ingroup utilities
+
+namespace etl
+{
+ //***************************************************************************
+ /// iota
+ /// Reverse engineered version of std::iota for non C++ 0x11 compilers.
+ /// Fills a range of elements with sequentially increasing values starting with <b>value</b>.
+ ///\param first An iterator to the first position to fill.
+ ///\param last An iterator to the last + 1 position.
+ ///\ingroup numeric
+ //***************************************************************************
+ template <typename TIterator, typename T>
+ void iota(TIterator first, TIterator last, T value)
+ {
+ while (first != last)
+ {
+ *first++ = value++;
+ }
+ }
+}
+
+#endif
+
diff --git a/lib/etl/observer.h b/lib/etl/observer.h
new file mode 100644
index 0000000..f46e425
--- /dev/null
+++ b/lib/etl/observer.h
@@ -0,0 +1,348 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_OBSERVER__
+#define __ETL_OBSERVER__
+
+//*****************************************************************************
+///\defgroup observer observer
+/// A templated implementation to simplify the creation of the observer pattern
+/// and attempts to eliminate certain runtime errors by turning them into compile errors.
+/// The pattern consists of two template classes.
+/// \li <b>Observer</b><br>
+/// This template may take up to eight notification types.
+/// Each notification type will generate a pure virtual 'notification'
+/// function. The class that inherits from this *must* define all
+/// of the 'notification' function overloads otherwise the object will
+/// remain 'abstract' and will not compile.
+/// This ensures that no overload can be forgotten.<br>
+///
+/// \li <b>observable</b><br>
+/// The class derived from this will be observed by the above class.
+/// It keeps a list of registered observers and will notify all
+/// of them with the notifications.
+///\ingroup patterns
+//*****************************************************************************
+
+#include <algorithm>
+#include "vector.h"
+#include "exception.h"
+#include "error_handler.h"
+
+#undef ETL_FILE
+#define ETL_FILE "18"
+
+namespace etl
+{
+ //***************************************************************************
+ ///\ingroup observer
+ /// The base class for observer exceptions.
+ //***************************************************************************
+ class observer_exception : public exception
+ {
+ public:
+
+ observer_exception(string_type what, string_type file_name, numeric_type line_number)
+ : exception(what, file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ ///\ingroup observer
+ /// The exception thrown when the observer list is full.
+ //***************************************************************************
+ class observer_list_full : public observer_exception
+ {
+ public:
+
+ observer_list_full(string_type file_name, numeric_type line_number)
+ : observer_exception(ETL_ERROR_TEXT("observer:full", ETL_FILE"A"), file_name, line_number)
+ {
+ }
+ };
+
+ //*********************************************************************
+ /// The object that is being observed.
+ ///\tparam TObserver The observer type.
+ ///\tparam MAX_OBSERVERS The maximum number of observers that can be accomodated.
+ ///\ingroup observer
+ //*********************************************************************
+ template <typename TObserver, const size_t MAX_OBSERVERS>
+ class observable
+ {
+ public:
+
+ typedef size_t size_type;
+
+ typedef etl::vector<TObserver*, MAX_OBSERVERS> Observer_List;
+
+ //*****************************************************************
+ /// Add an observer to the list.
+ /// If asserts or exceptions are enabled then an etl::observable_observer_list_full
+ /// is emitted if the observer list is already full.
+ ///\param observer A reference to the observer.
+ //*****************************************************************
+ void add_observer(TObserver& observer)
+ {
+ // See if we already have it in our list.
+ typename Observer_List::const_iterator i_observer = std::find(observer_list.begin(),
+ observer_list.end(),
+ &observer);
+
+ // Not there?
+ if (i_observer == observer_list.end())
+ {
+ // Is there enough room?
+ ETL_ASSERT(!observer_list.full(), ETL_ERROR(etl::observer_list_full));
+
+ // Add it.
+ observer_list.push_back(&observer);
+ }
+ }
+
+ //*****************************************************************
+ /// Remove a particular observer from the list.
+ ///\param observer A reference to the observer.
+ //*****************************************************************
+ void remove_observer(TObserver& observer)
+ {
+ // See if we have it in our list.
+ typename Observer_List::iterator i_observer = std::find(observer_list.begin(),
+ observer_list.end(),
+ &observer);
+
+ // Found it?
+ if (i_observer != observer_list.end())
+ {
+ // Erase it.
+ observer_list.erase(i_observer);
+ }
+ }
+
+ //*****************************************************************
+ /// Clear all observers from the list.
+ //*****************************************************************
+ void clear_observers()
+ {
+ observer_list.clear();
+ }
+
+ //*****************************************************************
+ /// Returns the number of observers.
+ //*****************************************************************
+ size_type number_of_observers() const
+ {
+ return observer_list.size();
+ }
+
+ //*****************************************************************
+ /// Notify all of the observers, sending them the notification.
+ ///\tparam TNotification the notification type.
+ ///\param n The notification.
+ //*****************************************************************
+ template <typename TNotification>
+ void notify_observers(TNotification n)
+ {
+ for (size_t i = 0; i < observer_list.size(); ++i)
+ {
+ observer_list[i]->notification(n);
+ }
+ }
+
+ private:
+
+ /// The list of observers.
+ Observer_List observer_list;
+ };
+
+ //*********************************************************************
+ /// The observer interface for eight notification types.
+ ///\ingroup observer
+ //*********************************************************************
+ template <typename T1,
+ typename T2 = void,
+ typename T3 = void,
+ typename T4 = void,
+ typename T5 = void,
+ typename T6 = void,
+ typename T7 = void,
+ typename T8 = void>
+ class observer
+ {
+ public:
+ virtual ~observer() {}
+ virtual void notification(T1) = 0;
+ virtual void notification(T2) = 0;
+ virtual void notification(T3) = 0;
+ virtual void notification(T4) = 0;
+ virtual void notification(T5) = 0;
+ virtual void notification(T6) = 0;
+ virtual void notification(T7) = 0;
+ virtual void notification(T8) = 0;
+ };
+
+ //*********************************************************************
+ /// The observer interface for seven notification types.
+ ///\ingroup observer
+ //*********************************************************************
+ template <typename T1,
+ typename T2,
+ typename T3,
+ typename T4,
+ typename T5,
+ typename T6,
+ typename T7>
+ class observer<T1, T2, T3, T4, T5, T6, T7>
+ {
+ public:
+
+ virtual ~observer() {}
+ virtual void notification(T1) = 0;
+ virtual void notification(T2) = 0;
+ virtual void notification(T3) = 0;
+ virtual void notification(T4) = 0;
+ virtual void notification(T5) = 0;
+ virtual void notification(T6) = 0;
+ virtual void notification(T7) = 0;
+ };
+
+ //*********************************************************************
+ /// The observer interface for six notification types.
+ ///\ingroup observer
+ //*********************************************************************
+ template <typename T1,
+ typename T2,
+ typename T3,
+ typename T4,
+ typename T5,
+ typename T6>
+ class observer<T1, T2, T3, T4, T5, T6>
+ {
+ public:
+
+ virtual ~observer() {}
+ virtual void notification(T1) = 0;
+ virtual void notification(T2) = 0;
+ virtual void notification(T3) = 0;
+ virtual void notification(T4) = 0;
+ virtual void notification(T5) = 0;
+ virtual void notification(T6) = 0;
+ };
+
+ //*********************************************************************
+ /// The observer interface for five notification types.
+ ///\ingroup observer
+ //*********************************************************************
+ template <typename T1,
+ typename T2,
+ typename T3,
+ typename T4,
+ typename T5>
+ class observer<T1, T2, T3, T4, T5>
+ {
+ public:
+
+ virtual ~observer() {}
+ virtual void notification(T1) = 0;
+ virtual void notification(T2) = 0;
+ virtual void notification(T3) = 0;
+ virtual void notification(T4) = 0;
+ virtual void notification(T5) = 0;
+ };
+
+ //*********************************************************************
+ /// The observer interface for four notification types.
+ ///\ingroup observer
+ //*********************************************************************
+ template <typename T1,
+ typename T2,
+ typename T3,
+ typename T4>
+ class observer<T1, T2, T3, T4>
+ {
+ public:
+
+ virtual ~observer() {}
+ virtual void notification(T1) = 0;
+ virtual void notification(T2) = 0;
+ virtual void notification(T3) = 0;
+ virtual void notification(T4) = 0;
+ };
+
+ //*********************************************************************
+ /// The observer interface for three notification types.
+ ///\ingroup observer
+ //*********************************************************************
+ template <typename T1,
+ typename T2,
+ typename T3>
+ class observer<T1, T2, T3>
+ {
+ public:
+
+ virtual ~observer() {}
+ virtual void notification(T1) = 0;
+ virtual void notification(T2) = 0;
+ virtual void notification(T3) = 0;
+ };
+
+ //*********************************************************************
+ /// The observer interface for two notification types.
+ ///\ingroup observer
+ //*********************************************************************
+ template <typename T1,
+ typename T2>
+ class observer<T1, T2>
+ {
+ public:
+
+ virtual ~observer() {}
+ virtual void notification(T1) = 0;
+ virtual void notification(T2) = 0;
+ };
+
+ //*********************************************************************
+ /// The observer interface for one notification type.
+ ///\ingroup observer
+ //*********************************************************************
+ template <typename T1>
+ class observer<T1>
+ {
+ public:
+
+ virtual ~observer() {}
+ virtual void notification(T1) = 0;
+ };
+}
+
+#undef ETL_FILE
+
+#endif
diff --git a/lib/etl/optional.h b/lib/etl/optional.h
new file mode 100644
index 0000000..3fb1c47
--- /dev/null
+++ b/lib/etl/optional.h
@@ -0,0 +1,442 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2015 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_OPTIONAL__
+#define __ETL_OPTIONAL__
+
+#include "alignment.h"
+#include "type_traits.h"
+#include "exception.h"
+#include "error_handler.h"
+
+namespace etl
+{
+ //*****************************************************************************
+ /// A null option type.
+ ///\ingroup utilities
+ //*****************************************************************************
+ class nullopt_t
+ {
+ public:
+
+ // Convertible to any type of null non-member pointer.
+ template<class T>
+ operator T*() const
+ {
+ return 0;
+ }
+
+ private:
+
+ // Can't take address of nullopt.
+ void operator&() const;
+ };
+
+ //*****************************************************************************
+ /// A null option.
+ ///\ingroup utilities
+ //*****************************************************************************
+ const nullopt_t nullopt = {};
+
+ //***************************************************************************
+ /// Exception for optional.
+ ///\ingroup list
+ //***************************************************************************
+ class optional_exception : public exception
+ {
+ public:
+
+ optional_exception(string_type what, string_type file_name, numeric_type line_number)
+ : exception(what, file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// Invalid exception for optional.
+ ///\ingroup list
+ //***************************************************************************
+ class optional_invalid : public optional_exception
+ {
+ public:
+
+ optional_invalid(string_type file_name, numeric_type line_number)
+ : optional_exception("optional: invalid", file_name, line_number)
+ {
+ }
+ };
+
+ //*****************************************************************************
+ /// An optional type.
+ /// If the optional type is not initialised then a type is not constructed.
+ ///\tparam The type to store.
+ ///\ingroup utilities
+ //*****************************************************************************
+ template <typename T>
+ class optional
+ {
+ public:
+
+ //***************************************************************************
+ /// Constructor.
+ //***************************************************************************
+ optional()
+ : valid(false)
+ {
+ }
+
+ //***************************************************************************
+ /// Constructor with nullopt.
+ //***************************************************************************
+ optional(etl::nullopt_t)
+ : valid(false)
+ {
+ }
+
+ //***************************************************************************
+ /// Copy constructor.
+ //***************************************************************************
+ optional(const optional& other)
+ : valid(bool(other))
+ {
+ if (valid)
+ {
+ new (storage.template get_address<T>()) T(other.value());
+ }
+ }
+
+ //***************************************************************************
+ /// Constructor from value type.
+ //***************************************************************************
+ optional(const T& value)
+ {
+ new (storage.template get_address<T>()) T(value);
+ valid = true;
+ }
+
+ //***************************************************************************
+ /// Destructor.
+ //***************************************************************************
+ ~optional()
+ {
+ if (valid)
+ {
+ storage.template get_reference<T>().~T();
+ }
+ }
+
+ //***************************************************************************
+ /// Assignment operator from nullopt.
+ //***************************************************************************
+ optional& operator =(etl::nullopt_t)
+ {
+ if (valid)
+ {
+ storage.template get_reference<T>().~T();
+ valid = false;
+ }
+
+ return *this;
+ }
+
+ //***************************************************************************
+ /// Assignment operator from optional.
+ //***************************************************************************
+ optional& operator =(const optional& other)
+ {
+ if (this != &other)
+ {
+ if (valid && !bool(other))
+ {
+ storage.template get_reference<T>().~T();
+ valid = false;
+ }
+ else if (bool(other))
+ {
+ if (valid)
+ {
+ storage.template get_reference<T>() = other.value();
+ }
+ else
+ {
+ new (storage.template get_address<T>()) T(other.value());
+ valid = true;
+ }
+ }
+ }
+
+ return *this;
+ }
+
+ //***************************************************************************
+ /// Assignment operator from value type.
+ //***************************************************************************
+ optional& operator =(const T& value)
+ {
+ if (valid)
+ {
+ storage.template get_reference<T>() = value;
+ }
+ else
+ {
+ new (storage.template get_address<T>()) T(value);
+ valid = true;
+ }
+
+ return *this;
+ }
+
+ //***************************************************************************
+ /// Pointer operator.
+ //***************************************************************************
+ T* operator ->()
+ {
+#ifdef _DEBUG
+ ETL_ASSERT(valid, ETL_ERROR(optional_invalid));
+#endif
+
+ return storage.template get_address<T>();
+ }
+
+ //***************************************************************************
+ /// Pointer operator.
+ //***************************************************************************
+ const T* operator ->() const
+ {
+#ifdef _DEBUG
+ ETL_ASSERT(valid, ETL_ERROR(optional_invalid));
+#endif
+
+ return storage.template get_address<T>();
+ }
+
+ //***************************************************************************
+ /// Dereference operator.
+ //***************************************************************************
+ T& operator *()
+ {
+#ifdef _DEBUG
+ ETL_ASSERT(valid, ETL_ERROR(optional_invalid));
+#endif
+
+ return storage.template get_reference<T>();
+ }
+
+ //***************************************************************************
+ /// Dereference operator.
+ //***************************************************************************
+ const T& operator *() const
+ {
+#ifdef _DEBUG
+ ETL_ASSERT(valid, ETL_ERROR(optional_invalid));
+#endif
+
+ return storage.template get_reference<T>();
+ }
+
+ //***************************************************************************
+ /// Bool conversion operator.
+ //***************************************************************************
+ explicit operator bool() const
+ {
+ return valid;
+ }
+
+ //***************************************************************************
+ /// Get a reference to the value.
+ //***************************************************************************
+ T& value()
+ {
+#ifdef _DEBUG
+ ETL_ASSERT(valid, ETL_ERROR(optional_invalid));
+#endif
+
+ return storage.template get_reference<T>();
+ }
+
+ //***************************************************************************
+ /// Get a const reference to the value.
+ //***************************************************************************
+ const T& value() const
+ {
+#ifdef _DEBUG
+ ETL_ASSERT(valid, ETL_ERROR(optional_invalid));
+#endif
+
+ return storage.template get_reference<T>();
+ }
+
+ //***************************************************************************
+ /// Gets the value or a default if no valid.
+ //***************************************************************************
+ T value_or(T default_value) const
+ {
+ return valid ? value() : default_value;
+ }
+
+ //***************************************************************************
+ /// Swaps this value with another.
+ //***************************************************************************
+ void swap(optional& other)
+ {
+ optional temp(*this);
+ *this = other;
+ other = temp;
+ }
+
+ private:
+
+ typename etl::aligned_storage_as<sizeof(T), T>::type storage;
+ bool valid;
+ };
+}
+
+//*************************************************************************
+/// Swaps the values.
+//*************************************************************************
+template <typename T>
+void swap(etl::optional<T>& lhs, etl::optional<T>& rhs)
+{
+ lhs.swap(rhs);
+}
+
+//***************************************************************************
+/// Equality operator.
+//***************************************************************************
+template <typename T>
+bool operator ==(const etl::optional<T>& lhs, const etl::optional<T>& rhs)
+{
+ if (bool(lhs) != bool(rhs))
+ {
+ return false;
+ }
+ else if (!bool(lhs) && !bool(rhs))
+ {
+ return true;
+ }
+ else
+ {
+ return lhs.value() == rhs.value();
+ }
+}
+
+//***************************************************************************
+/// Less than operator.
+//***************************************************************************
+template <typename T>
+bool operator <(const etl::optional<T>& lhs, const etl::optional<T>& rhs)
+{
+ if (!bool(rhs))
+ {
+ return false;
+ }
+ else if (!bool(lhs))
+ {
+ return true;
+ }
+ else
+ {
+ return lhs.value() < rhs.value();
+ }
+}
+
+//***************************************************************************
+/// Equality operator.
+//***************************************************************************
+template <typename T>
+bool operator ==(const etl::optional<T>& lhs, etl::nullopt_t)
+{
+ return !bool(lhs);
+}
+
+//***************************************************************************
+/// Equality operator.
+//***************************************************************************
+template <typename T>
+bool operator ==(etl::nullopt_t, const etl::optional<T>& rhs)
+{
+ return false;
+}
+
+//***************************************************************************
+/// Less than operator.
+//***************************************************************************
+template <typename T>
+bool operator <(const etl::optional<T>& lhs, etl::nullopt_t)
+{
+ return !bool(lhs);
+}
+
+//***************************************************************************
+/// Less than operator.
+//***************************************************************************
+template <typename T>
+bool operator <(etl::nullopt_t, const etl::optional<T>& rhs)
+{
+ return bool(rhs);
+}
+
+//***************************************************************************
+/// Equality operator.
+//**************************************************************************
+template <typename T>
+bool operator ==(const etl::optional<T>& lhs, const T& rhs)
+{
+ return bool(lhs) ? lhs.value() == rhs : false;
+}
+
+//***************************************************************************
+/// Equality operator.
+//**************************************************************************
+template <typename T>
+bool operator ==(const T& value, const etl::optional<T>& rhs)
+{
+ return bool(rhs) ? rhs.value() == value : false;
+}
+
+//***************************************************************************
+/// Less than operator.
+//***************************************************************************
+template <typename T>
+bool operator <(const etl::optional<T>& lhs, const T& rhs)
+{
+ return bool(lhs) ? lhs.value() < rhs : true;
+}
+
+//***************************************************************************
+/// Make an optional.
+//***************************************************************************
+template <typename T>
+etl::optional<typename etl::decay<T>::type> make_optional(T& value)
+{
+ return etl::optional<typename etl::decay<T>::type>(value);
+}
+
+#endif
diff --git a/lib/etl/parameter_type.h b/lib/etl/parameter_type.h
new file mode 100644
index 0000000..bdc73e0
--- /dev/null
+++ b/lib/etl/parameter_type.h
@@ -0,0 +1,63 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_PARAMETER__
+#define __ETL_PARAMETER__
+
+#include "type_traits.h"
+
+namespace etl
+{
+ //*************************************************************************
+ /// Determine how to pass parameters.
+ //*************************************************************************
+ template <typename T, const bool should_pass_by_value = is_fundamental<T>::value || is_pointer<T>::value>
+ struct parameter_type;
+
+ //*************************************************************************
+ /// Pass by value.
+ //*************************************************************************
+ template <typename T>
+ struct parameter_type<T, true>
+ {
+ typedef T type;
+ };
+
+ //*************************************************************************
+ /// Pass by const reference.
+ //*************************************************************************
+ template <typename T>
+ struct parameter_type<T, false>
+ {
+ typedef const T& type;
+ };
+}
+
+#endif
diff --git a/lib/etl/pearson.cpp b/lib/etl/pearson.cpp
new file mode 100644
index 0000000..ce4742d
--- /dev/null
+++ b/lib/etl/pearson.cpp
@@ -0,0 +1,58 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2015 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#include <stdint.h>
+
+namespace etl
+{
+ //***************************************************************************
+ /// Pearson lookup table
+ /// \ingroup pearson
+ //***************************************************************************
+ extern const uint8_t PEARSON_LOOKUP[] =
+ {
+ 228, 39, 61, 95, 227, 187, 0, 197, 31, 189, 161, 222, 34, 15, 221, 246,
+ 19, 234, 6, 50, 113, 3, 91, 63, 77, 245, 144, 2, 183, 196, 25, 226,
+ 97, 126, 48, 59, 217, 4, 100, 145, 12, 88, 203, 149, 80, 154, 38, 27,
+ 224, 218, 158, 115, 202, 79, 53, 83, 242, 36, 139, 131, 136, 191, 42, 170,
+ 23, 99, 156, 51, 143, 60, 233, 206, 62, 108, 17, 67, 81, 71, 93, 195,
+ 26, 231, 247, 96, 24, 200, 176, 209, 152, 212, 138, 165, 75, 185, 130, 248,
+ 125, 110, 10, 116, 201, 90, 69, 204, 85, 251, 78, 157, 47, 184, 169, 141,
+ 134, 230, 89, 21, 146, 46, 55, 128, 148, 207, 216, 11, 114, 199, 103, 102,
+ 166, 244, 5, 104, 225, 160, 132, 28, 172, 65, 121, 140, 153, 119, 198, 210,
+ 58, 87, 117, 177, 33, 22, 13, 37, 49, 174, 109, 40, 73, 211, 18, 167,
+ 164, 252, 168, 74, 30, 173, 35, 98, 66, 193, 94, 175, 86, 54, 179, 122,
+ 220, 151, 192, 29, 133, 254, 155, 127, 240, 232, 190, 180, 8, 68, 236, 20,
+ 137, 92, 219, 208, 52, 250, 147, 142, 111, 112, 120, 45, 135, 255, 123, 229,
+ 57, 182, 243, 124, 186, 253, 7, 237, 9, 16, 70, 171, 235, 107, 223, 118,
+ 215, 178, 194, 181, 43, 188, 106, 105, 64, 241, 84, 238, 159, 44, 32, 76,
+ 213, 163, 150, 101, 129, 14, 249, 205, 214, 1, 41, 56, 162, 72, 239, 82
+ } ;
+}
diff --git a/lib/etl/pearson.h b/lib/etl/pearson.h
new file mode 100644
index 0000000..4952d88
--- /dev/null
+++ b/lib/etl/pearson.h
@@ -0,0 +1,165 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_PEARSON__
+#define __ETL_PEARSON__
+
+#include <stdint.h>
+
+#include "platform.h"
+#include "static_assert.h"
+#include "type_traits.h"
+#include "endian.h"
+#include "ihash.h"
+#include "array.h"
+#include "container.h"
+
+#if defined(ETL_COMPILER_KEIL)
+#pragma diag_suppress 1300
+#endif
+
+///\defgroup pearson Pearson hash calculation
+///\ingroup pearson
+
+namespace etl
+{
+ //***************************************************************************
+ /// Pearson lookup table
+ /// \ingroup pearson
+ //***************************************************************************
+ extern const uint8_t PEARSON_LOOKUP[];
+
+ //***************************************************************************
+ /// Calculates a Pearson hash
+ ///\tparam HASH_LENGTH The number of elements in the hash.
+ /// \ingroup pearson
+ //***************************************************************************
+ template <const size_t HASH_LENGTH>
+ class pearson
+ {
+ public:
+
+ typedef etl::array<uint8_t, HASH_LENGTH> value_type;
+
+ //*************************************************************************
+ /// Default constructor.
+ //*************************************************************************
+ pearson()
+ : first(true)
+ {
+ reset();
+ }
+
+ //*************************************************************************
+ /// Constructor from range.
+ /// \param begin Start of the range.
+ /// \param end End of the range.
+ //*************************************************************************
+ template<typename TIterator>
+ pearson(TIterator begin, const TIterator end)
+ : first(true)
+ {
+ STATIC_ASSERT(sizeof(typename std::iterator_traits<TIterator>::value_type) == 1, "Type not supported");
+
+ reset();
+ add(begin, end);
+ }
+
+ //*************************************************************************
+ /// Resets the hash to the initial state.
+ //*************************************************************************
+ void reset()
+ {
+ hash.fill(0);
+ }
+
+ //*************************************************************************
+ /// Adds a range.
+ /// \param begin
+ /// \param end
+ //*************************************************************************
+ template<typename TIterator>
+ void add(TIterator begin, const TIterator end)
+ {
+ STATIC_ASSERT(sizeof(typename std::iterator_traits<TIterator>::value_type) == 1, "Type not supported");
+
+ while (begin != end)
+ {
+ add(*begin++);
+ }
+ }
+
+ //*************************************************************************
+ /// \param value The char to add to the hash.
+ //*************************************************************************
+ void add(uint8_t value)
+ {
+ if (first)
+ {
+ for (size_t i = 0; i < HASH_LENGTH; ++i)
+ {
+ hash[i] = PEARSON_LOOKUP[(uint32_t(value) + i) % 256];
+ }
+
+ first = false;
+ }
+ else
+ {
+ for (size_t i = 0; i < HASH_LENGTH; ++i)
+ {
+ hash[i] = PEARSON_LOOKUP[hash[i] ^ value];
+ }
+ }
+ }
+
+ //*************************************************************************
+ /// Gets the hash value.
+ //*************************************************************************
+ value_type value() const
+ {
+ return hash;
+ }
+
+ //*************************************************************************
+ /// Conversion operator to value_type.
+ //*************************************************************************
+ operator value_type () const
+ {
+ return value();
+ }
+
+ private:
+
+ bool first;
+ value_type hash;
+ };
+}
+
+#endif
diff --git a/lib/etl/platform.h b/lib/etl/platform.h
new file mode 100644
index 0000000..1365055
--- /dev/null
+++ b/lib/etl/platform.h
@@ -0,0 +1,73 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+// Define the platform.
+// For FreeRTOS you must define ETL_PLATFORM_FREERTOS in the project settings.
+#if defined(__linux__)
+#define ETL_PLATFORM_LINUX
+#elif defined(WIN32) || defined(WIN64)
+#define ETL_PLATFORM_WINDOWS
+#elif defined(__VXWORKS__) || defined(_WRS_VXWORKS_MAJOR)
+#define ETL_PLATFORM_VXWORKS
+#elif defined(__QNX__) || defined(__QNXNTO__)
+#define ETL_PLATFORM_QNX
+#elif defined(_WIN32_WCE)
+#define ETL_PLATFORM_WINDOWS_CE
+#else
+#define ETL_PLATFORM_GENERIC
+#endif
+
+// Define the compiler.
+#if defined(__IAR_SYSTEMS_ICC__)
+#define ETL_COMPILER_IAR
+#elif defined(__KEIL__) && !defined(__GNUC__)
+#define ETL_COMPILER_KEIL
+#elif defined(__ghs__)
+#define ETL_COMPILER_GREEN_HILLS
+#elif defined(__INTEL_COMPILER)
+#define ETL_COMPILER_INTEL
+#elif defined(_MSC_VER)
+#define ETL_COMPILER_MICROSOFT
+#elif defined(__GNUC__)
+#define ETL_COMPILER_GCC
+#elif defined(__TI_COMPILER_VERSION__) && defined(__MSP430__)
+#define ETL_COMPILER_TI_MSP430
+#else
+#define ETL_COMPILER_GENERIC
+#endif
+
+#if (defined(ETL_COMPILER_MICROSOFT) && (_MSC_VER < 1600)) || \
+ defined(ETL_COMPILER_KEIL) || \
+ defined(ETL_COMPILER_TI_MSP430) || \
+ defined(ETL_COMPILER_IAR) || \
+ (defined(ETL_COMPILER_GCC) && (__cplusplus < 201103L))
+#define NO_NULLPTR_SUPPORT
+#define NO_LARGE_CHAR_SUPPORT
+#endif
diff --git a/lib/etl/pool.h b/lib/etl/pool.h
new file mode 100644
index 0000000..eb98e2e
--- /dev/null
+++ b/lib/etl/pool.h
@@ -0,0 +1,91 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_POOL__
+#define __ETL_POOL__
+
+#include "alignment.h"
+#include "array.h"
+#include "bitset.h"
+#include "ipool.h"
+
+#include <iterator>
+
+//*****************************************************************************
+///\defgroup pool pool
+/// A fixed capacity pool.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+ //*************************************************************************
+ /// A templated pool implementation that uses a fixed size pool.
+ ///\ingroup pool
+ //*************************************************************************
+ template <typename T, const size_t SIZE_>
+ class pool : public ipool<T>
+ {
+ public:
+
+ static const size_t SIZE = SIZE_;
+
+ //*************************************************************************
+ /// Constructor
+ //*************************************************************************
+ pool()
+ : ipool<T>(reinterpret_cast<T*>(&buffer[0]), in_use, SIZE)
+ {
+ }
+
+ //*************************************************************************
+ /// Destructor
+ //*************************************************************************
+ ~pool()
+ {
+ ipool<T>::release_all();
+ }
+
+ private:
+
+ ///< The memory for the pool of objects.
+ typename etl::aligned_storage<sizeof(T), etl::alignment_of<T>::value>::type buffer[SIZE];
+
+ ///< The set of flags that indicate which items are free in the pool.
+ bitset<SIZE> in_use;
+
+ // Should not be copied.
+ pool(const pool&);
+ pool& operator =(const pool&);
+ };
+}
+
+#endif
+
diff --git a/lib/etl/power.h b/lib/etl/power.h
new file mode 100644
index 0000000..421806c
--- /dev/null
+++ b/lib/etl/power.h
@@ -0,0 +1,185 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_POW__
+#define __ETL_POW__
+
+#include <stddef.h>
+#include "log.h"
+
+///\defgroup power power
+/// power<N, POWER> : Calculates N to the power POWER.
+///\ingroup maths
+
+namespace etl
+{
+ //***************************************************************************
+ ///\ingroup power
+ /// Calculates powers.
+ ///\note Only supports positive N.
+ //***************************************************************************
+ template <const size_t NV, const size_t POWER>
+ struct power
+ {
+ static const uint64_t value = NV * power<NV, POWER - 1>::value;
+ };
+
+ //***************************************************************************
+ /// Calculates powers.
+ ///\note Only supports positive N.
+ /// Specialisation for POWER == 0.
+ //***************************************************************************
+ template <const size_t NV>
+ struct power<NV, 0>
+ {
+ static const uint64_t value = 1;
+ };
+
+ //***************************************************************************
+ /// Declaration of static 'value' for power.
+ //***************************************************************************
+ template <const size_t NV, const size_t POWER> const uint64_t power<NV, POWER>::value;
+
+ //***************************************************************************
+ ///\ingroup power
+ /// Calculates the rounded up power of 2.
+ //***************************************************************************
+ template <const size_t NV>
+ struct power_of_2_round_up
+ {
+ enum value_type
+ {
+ value = 1 << (etl::log2<NV - 1>::value + 1)
+ };
+ };
+
+ //***************************************************************************
+ ///\ingroup power
+ /// Calculates the rounded up power of 2.
+ /// Specialisation for 0.
+ //***************************************************************************
+ template <>
+ struct power_of_2_round_up<0>
+ {
+ enum value_type
+ {
+ value = 2
+ };
+ };
+
+ //***************************************************************************
+ ///\ingroup power
+ /// Calculates the rounded down power of 2.
+ //***************************************************************************
+ template <const size_t NV>
+ struct power_of_2_round_down
+ {
+ enum value_type
+ {
+ value = 1 << (etl::log2<NV - 1>::value)
+ };
+ };
+
+ //***************************************************************************
+ ///\ingroup power
+ /// Calculates the rounded down power of 2.
+ /// Specialisation for 0.
+ //***************************************************************************
+ template <>
+ struct power_of_2_round_down<0>
+ {
+ enum value_type
+ {
+ value = 2
+ };
+ };
+
+ //***************************************************************************
+ ///\ingroup power
+ /// Calculates the rounded down power of 2.
+ /// Specialisation for 1.
+ //***************************************************************************
+ template <>
+ struct power_of_2_round_down<1>
+ {
+ enum value_type
+ {
+ value = 2
+ };
+ };
+
+ //***************************************************************************
+ ///\ingroup power
+ /// Calculates the rounded down power of 2.
+ /// Specialisation for 2.
+ //***************************************************************************
+ template <>
+ struct power_of_2_round_down<2>
+ {
+ enum value_type
+ {
+ value = 2
+ };
+ };
+
+ //***************************************************************************
+ ///\ingroup power
+ /// Checks if N is a power of 2.
+ //***************************************************************************
+ template <const size_t NV>
+ struct is_power_of_2
+ {
+ static const bool value = (NV & (NV - 1)) == 0;
+ };
+
+ //***************************************************************************
+ ///\ingroup power
+ /// Checks if N is a power of 2.
+ /// Specialisation for 0.
+ //***************************************************************************
+ template <>
+ struct is_power_of_2<0>
+ {
+ static const bool value = false;
+ };
+
+ //***************************************************************************
+ ///\ingroup power
+ /// Checks if N is a power of 2.
+ /// Specialisation for 1.
+ //***************************************************************************
+ template <>
+ struct is_power_of_2<1>
+ {
+ static const bool value = false;
+ };
+}
+
+#endif
diff --git a/lib/etl/priority_queue.h b/lib/etl/priority_queue.h
new file mode 100644
index 0000000..507c86c
--- /dev/null
+++ b/lib/etl/priority_queue.h
@@ -0,0 +1,115 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2015 jwellbelove, rlindeman
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_PRIORITY_QUEUE__
+#define __ETL_PRIORITY_QUEUE__
+
+#include <stddef.h>
+#include <functional>
+
+#include "ipriority_queue.h"
+#include "container.h"
+#include "vector.h"
+
+//*****************************************************************************
+///\defgroup queue queue
+/// A priority queue with the capacity defined at compile time,
+/// written in the STL style.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+ //***************************************************************************
+ ///\ingroup priority_queue
+ /// A fixed capacity priority queue.
+ /// This queue does not support concurrent access by different threads.
+ /// \tparam T The type this queue should support.
+ /// \tparam SIZE The maximum capacity of the queue.
+ //***************************************************************************
+ template <typename T, const size_t SIZE, typename TContainer = etl::vector<T, SIZE>, typename TCompare = std::less<typename TContainer::value_type> >
+ class priority_queue : public ipriority_queue<T, TContainer, TCompare>
+ {
+ public:
+
+ //*************************************************************************
+ /// Default constructor.
+ //*************************************************************************
+ priority_queue()
+ : ipriority_queue<T, TContainer, TCompare>()
+ {
+ }
+
+ //*************************************************************************
+ /// Copy constructor
+ //*************************************************************************
+ priority_queue(const priority_queue& rhs)
+ : ipriority_queue<T, TContainer, TCompare>()
+ {
+ ipriority_queue<T, TContainer, TCompare>::clone(rhs);
+ }
+
+ //*************************************************************************
+ /// Constructor, from an iterator range.
+ ///\tparam TIterator The iterator type.
+ ///\param first The iterator to the first element.
+ ///\param last The iterator to the last element + 1.
+ //*************************************************************************
+ template <typename TIterator>
+ priority_queue(TIterator first, TIterator last)
+ : ipriority_queue<T, TContainer, TCompare>()
+ {
+ ipriority_queue<T, TContainer, TCompare>::assign(first, last);
+ }
+
+ //*************************************************************************
+ /// Destructor.
+ //*************************************************************************
+ ~priority_queue()
+ {
+ ipriority_queue<T, TContainer, TCompare>::clear();
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ priority_queue& operator = (const priority_queue& rhs)
+ {
+ if (&rhs != this)
+ {
+ ipriority_queue<T, TContainer, TCompare>::clone(rhs);
+ }
+
+ return *this;
+ }
+ };
+}
+
+#endif
diff --git a/lib/etl/private/deque_base.h b/lib/etl/private/deque_base.h
new file mode 100644
index 0000000..7975543
--- /dev/null
+++ b/lib/etl/private/deque_base.h
@@ -0,0 +1,179 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_IN_IDEQUE_H__
+#error This header is a private element of etl::deque & etl::ideque
+#endif
+
+#ifndef __ETL_DEQUE_BASE__
+#define __ETL_DEQUE_BASE__
+
+#include <stddef.h>
+
+#include "../exception.h"
+#include "../error_handler.h"
+
+#undef ETL_FILE
+#define ETL_FILE "1"
+
+namespace etl
+{
+ //***************************************************************************
+ /// Exception base for deques
+ ///\ingroup deque
+ //***************************************************************************
+ class deque_exception : public exception
+ {
+ public:
+
+ deque_exception(string_type what, string_type file_name, numeric_type line_number)
+ : exception(what, file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// Deque full exception.
+ ///\ingroup deque
+ //***************************************************************************
+ class deque_full : public deque_exception
+ {
+ public:
+
+ deque_full(string_type file_name, numeric_type line_number)
+ : deque_exception(ETL_ERROR_TEXT("deque:full", ETL_FILE"A"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// Deque empty exception.
+ ///\ingroup deque
+ //***************************************************************************
+ class deque_empty : public deque_exception
+ {
+ public:
+
+ deque_empty(string_type file_name, numeric_type line_number)
+ : deque_exception(ETL_ERROR_TEXT("deque:empty", ETL_FILE"B"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// Deque out of bounds exception.
+ ///\ingroup deque
+ //***************************************************************************
+ class deque_out_of_bounds : public deque_exception
+ {
+ public:
+
+ deque_out_of_bounds(string_type file_name, numeric_type line_number)
+ : deque_exception(ETL_ERROR_TEXT("deque:bounds", ETL_FILE"C"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// The base class for all templated deque types.
+ ///\ingroup deque
+ //***************************************************************************
+ class deque_base
+ {
+ public:
+
+ typedef size_t size_type;
+
+ //*************************************************************************
+ /// Gets the current size of the deque.
+ ///\return The current size of the deque.
+ //*************************************************************************
+ size_type size() const
+ {
+ return current_size;
+ }
+
+ //*************************************************************************
+ /// Checks the 'empty' state of the deque.
+ ///\return <b>true</b> if empty.
+ //*************************************************************************
+ bool empty() const
+ {
+ return (current_size == 0);
+ }
+
+ //*************************************************************************
+ /// Checks the 'full' state of the deque.
+ ///\return <b>true</b> if full.
+ //*************************************************************************
+ bool full() const
+ {
+ return current_size == MAX_SIZE;
+ }
+
+ //*************************************************************************
+ /// Returns the maximum possible size of the deque.
+ ///\return The maximum size of the deque.
+ //*************************************************************************
+ size_type max_size() const
+ {
+ return MAX_SIZE;
+ }
+
+ //*************************************************************************
+ /// Returns the remaining capacity.
+ ///\return The remaining capacity.
+ //*************************************************************************
+ size_t available() const
+ {
+ return max_size() - size();
+ }
+
+ protected:
+
+ //*************************************************************************
+ /// Constructor.
+ //*************************************************************************
+ deque_base(size_t max_size, size_t buffer_size)
+ : current_size(0),
+ MAX_SIZE(max_size),
+ BUFFER_SIZE(buffer_size)
+ {
+ }
+
+ size_type current_size; ///< The current number of elements in the deque.
+ const size_type MAX_SIZE; ///< The maximum number of elements in the deque.
+ const size_type BUFFER_SIZE; ///< The number of elements in the buffer.
+ };
+}
+
+#undef ETL_FILE
+
+#endif
diff --git a/lib/etl/private/flat_map_base.h b/lib/etl/private/flat_map_base.h
new file mode 100644
index 0000000..16fd858
--- /dev/null
+++ b/lib/etl/private/flat_map_base.h
@@ -0,0 +1,171 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2015 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_IN_IFLAT_MAP_H__
+#error This header is a private element of etl::flat_map & etl::iflat_map
+#endif
+
+#ifndef __ETL_FLAT_MAP_BASE__
+#define __ETL_FLAT_MAP_BASE__
+
+#include <stddef.h>
+
+#include "../exception.h"
+#include "../ivector.h"
+#include "../error_handler.h"
+
+#undef ETL_FILE
+#define ETL_FILE "2"
+
+namespace etl
+{
+ //***************************************************************************
+ ///\ingroup flat_map
+ /// Exception base for flat_maps
+ //***************************************************************************
+ class flat_map_exception : public exception
+ {
+ public:
+
+ flat_map_exception(string_type what, string_type file_name, numeric_type line_number)
+ : exception(what, file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ ///\ingroup flat_map
+ /// Vector full exception.
+ //***************************************************************************
+ class flat_map_full : public flat_map_exception
+ {
+ public:
+
+ flat_map_full(string_type file_name, numeric_type line_number)
+ : flat_map_exception(ETL_ERROR_TEXT("flat_map: full", ETL_FILE"A"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ ///\ingroup flat_map
+ /// Vector out of bounds exception.
+ //***************************************************************************
+ class flat_map_out_of_bounds : public flat_map_exception
+ {
+ public:
+
+ flat_map_out_of_bounds(string_type file_name, numeric_type line_number)
+ : flat_map_exception(ETL_ERROR_TEXT("flat_map:bounds", ETL_FILE"B"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ ///\ingroup flat_map
+ /// The base class for all templated flat_map types.
+ //***************************************************************************
+ class flat_map_base
+ {
+ public:
+
+ typedef size_t size_type;
+
+ //*************************************************************************
+ /// Gets the current size of the flat_map.
+ ///\return The current size of the flat_map.
+ //*************************************************************************
+ size_type size() const
+ {
+ return vbase.size();
+ }
+
+ //*************************************************************************
+ /// Checks the 'empty' state of the flat_map.
+ ///\return <b>true</b> if empty.
+ //*************************************************************************
+ bool empty() const
+ {
+ return vbase.empty();
+ }
+
+ //*************************************************************************
+ /// Checks the 'full' state of the flat_map.
+ ///\return <b>true</b> if full.
+ //*************************************************************************
+ bool full() const
+ {
+ return vbase.full();
+ }
+
+ //*************************************************************************
+ /// Returns the capacity of the flat_map.
+ ///\return The capacity of the flat_map.
+ //*************************************************************************
+ size_type capacity() const
+ {
+ return vbase.capacity();
+ }
+
+ //*************************************************************************
+ /// Returns the maximum possible size of the flat_map.
+ ///\return The maximum size of the flat_map.
+ //*************************************************************************
+ size_type max_size() const
+ {
+ return vbase.max_size();
+ }
+
+ //*************************************************************************
+ /// Returns the remaining capacity.
+ ///\return The remaining capacity.
+ //*************************************************************************
+ size_t available() const
+ {
+ return vbase.available();
+ }
+
+ protected:
+
+ //*************************************************************************
+ /// Constructor.
+ //*************************************************************************
+ flat_map_base(vector_base& vbase)
+ : vbase(vbase)
+ {
+ }
+
+ vector_base& vbase;
+ };
+}
+
+#undef ETL_FILE
+
+#endif
diff --git a/lib/etl/private/flat_multimap_base.h b/lib/etl/private/flat_multimap_base.h
new file mode 100644
index 0000000..eb9840f
--- /dev/null
+++ b/lib/etl/private/flat_multimap_base.h
@@ -0,0 +1,155 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2015 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_IN_IFLAT_MULTIMAP_H__
+#error This header is a private element of etl::flat_multimap & etl::iflat_multimap
+#endif
+
+#ifndef __ETL_FLAT_MULTIMAP_BASE__
+#define __ETL_FLAT_MULTIMAP_BASE__
+
+#include <stddef.h>
+
+#include "../exception.h"
+#include "../ivector.h"
+#include "../error_handler.h"
+
+#undef ETL_FILE
+#define ETL_FILE "3"
+
+namespace etl
+{
+ //***************************************************************************
+ ///\ingroup flat_multimap
+ /// Exception base for flat_multimaps
+ //***************************************************************************
+ class flat_multimap_exception : public exception
+ {
+ public:
+
+ flat_multimap_exception(string_type what, string_type file_name, numeric_type line_number)
+ : exception(what, file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ ///\ingroup flat_multimap
+ /// Vector full exception.
+ //***************************************************************************
+ class flat_multimap_full : public flat_multimap_exception
+ {
+ public:
+
+ flat_multimap_full(string_type file_name, numeric_type line_number)
+ : flat_multimap_exception(ETL_ERROR_TEXT("flat_multimap:full", ETL_FILE"A"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ ///\ingroup flat_multimap
+ /// The base class for all templated flat_multimap types.
+ //***************************************************************************
+ class flat_multimap_base
+ {
+ public:
+
+ typedef size_t size_type;
+
+ //*************************************************************************
+ /// Gets the current size of the flat_multimap.
+ ///\return The current size of the flat_multimap.
+ //*************************************************************************
+ size_type size() const
+ {
+ return vbase.size();
+ }
+
+ //*************************************************************************
+ /// Checks the 'empty' state of the flat_multimap.
+ ///\return <b>true</b> if empty.
+ //*************************************************************************
+ bool empty() const
+ {
+ return vbase.empty();
+ }
+
+ //*************************************************************************
+ /// Checks the 'full' state of the flat_multimap.
+ ///\return <b>true</b> if full.
+ //*************************************************************************
+ bool full() const
+ {
+ return vbase.full();
+ }
+
+ //*************************************************************************
+ /// Returns the capacity of the flat_multimap.
+ ///\return The capacity of the flat_multimap.
+ //*************************************************************************
+ size_type capacity() const
+ {
+ return vbase.capacity();
+ }
+
+ //*************************************************************************
+ /// Returns the maximum possible size of the flat_multimap.
+ ///\return The maximum size of the flat_multimap.
+ //*************************************************************************
+ size_type max_size() const
+ {
+ return vbase.max_size();
+ }
+
+ //*************************************************************************
+ /// Returns the remaining capacity.
+ ///\return The remaining capacity.
+ //*************************************************************************
+ size_t available() const
+ {
+ return vbase.available();
+ }
+
+ protected:
+
+ //*************************************************************************
+ /// Constructor.
+ //*************************************************************************
+ flat_multimap_base(vector_base& vbase)
+ : vbase(vbase)
+ {
+ }
+
+ vector_base& vbase;
+ };
+}
+
+#endif
diff --git a/lib/etl/private/flat_multiset_base.h b/lib/etl/private/flat_multiset_base.h
new file mode 100644
index 0000000..4b495dd
--- /dev/null
+++ b/lib/etl/private/flat_multiset_base.h
@@ -0,0 +1,157 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2015 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_IN_IFLAT_MULTISET_H__
+#error This header is a private element of etl::flat_multiset & etl::iflat_multiset
+#endif
+
+#ifndef __ETL_FLAT_MULTISET_BASE__
+#define __ETL_FLAT_MULTISET_BASE__
+
+#include <stddef.h>
+
+#include "../exception.h"
+#include "../ivector.h"
+#include "../error_handler.h"
+
+#undef ETL_FILE
+#define ETL_FILE "4"
+
+namespace etl
+{
+ //***************************************************************************
+ ///\ingroup flat_multiset
+ /// Exception base for flat_multisets
+ //***************************************************************************
+ class flat_multiset_exception : public exception
+ {
+ public:
+
+ flat_multiset_exception(string_type what, string_type file_name, numeric_type line_number)
+ : exception(what, file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ ///\ingroup flat_multiset
+ /// Flat multiset full exception.
+ //***************************************************************************
+ class flat_multiset_full : public flat_multiset_exception
+ {
+ public:
+
+ flat_multiset_full(string_type file_name, numeric_type line_number)
+ : flat_multiset_exception(ETL_ERROR_TEXT("flat_multiset:full", ETL_FILE"A"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ ///\ingroup flat_multiset
+ /// The base class for all templated flat_multiset types.
+ //***************************************************************************
+ class flat_multiset_base
+ {
+ public:
+
+ typedef size_t size_type;
+
+ //*************************************************************************
+ /// Gets the current size of the flat_multiset.
+ ///\return The current size of the flat_multiset.
+ //*************************************************************************
+ size_type size() const
+ {
+ return vbase.size();
+ }
+
+ //*************************************************************************
+ /// Checks the 'empty' state of the flat_multiset.
+ ///\return <b>true</b> if empty.
+ //*************************************************************************
+ bool empty() const
+ {
+ return vbase.empty();
+ }
+
+ //*************************************************************************
+ /// Checks the 'full' state of the flat_multiset.
+ ///\return <b>true</b> if full.
+ //*************************************************************************
+ bool full() const
+ {
+ return vbase.full();
+ }
+
+ //*************************************************************************
+ /// Returns the capacity of the flat_multiset.
+ ///\return The capacity of the flat_multiset.
+ //*************************************************************************
+ size_type capacity() const
+ {
+ return vbase.capacity();
+ }
+
+ //*************************************************************************
+ /// Returns the maximum possible size of the flat_multiset.
+ ///\return The maximum size of the flat_multiset.
+ //*************************************************************************
+ size_type max_size() const
+ {
+ return vbase.max_size();
+ }
+
+ //*************************************************************************
+ /// Returns the remaining capacity.
+ ///\return The remaining capacity.
+ //*************************************************************************
+ size_t available() const
+ {
+ return vbase.available();
+ }
+
+ protected:
+
+ //*************************************************************************
+ /// Constructor.
+ //*************************************************************************
+ flat_multiset_base(vector_base& vbase)
+ : vbase(vbase)
+ {
+ }
+
+ vector_base& vbase;
+ };
+}
+
+#undef ETL_FILE
+
+#endif
diff --git a/lib/etl/private/flat_set_base.h b/lib/etl/private/flat_set_base.h
new file mode 100644
index 0000000..22d1c58
--- /dev/null
+++ b/lib/etl/private/flat_set_base.h
@@ -0,0 +1,171 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2015 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_IN_IFLAT_SET_H__
+#error This header is a private element of etl::flat_set & etl::iflat_set
+#endif
+
+#ifndef __ETL_FLAT_SET_BASE__
+#define __ETL_FLAT_SET_BASE__
+
+#include <stddef.h>
+
+#include "../exception.h"
+#include "../ivector.h"
+#include "../error_handler.h"
+
+#undef ETL_FILE
+#define ETL_FILE "5"
+
+namespace etl
+{
+ //***************************************************************************
+ ///\ingroup flat_set
+ /// Exception base for flat_sets
+ //***************************************************************************
+ class flat_set_exception : public exception
+ {
+ public:
+
+ flat_set_exception(string_type what, string_type file_name, numeric_type line_number)
+ : exception(what, file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ ///\ingroup flat_set
+ /// Vector full exception.
+ //***************************************************************************
+ class flat_set_full : public flat_set_exception
+ {
+ public:
+
+ flat_set_full(string_type file_name, numeric_type line_number)
+ : flat_set_exception(ETL_ERROR_TEXT("flat_set:full", ETL_FILE"A"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ ///\ingroup flat_set
+ /// Vector iterator exception.
+ //***************************************************************************
+ class flat_set_iterator : public flat_set_exception
+ {
+ public:
+
+ flat_set_iterator(string_type file_name, numeric_type line_number)
+ : flat_set_exception(ETL_ERROR_TEXT("flat_set:iterator", ETL_FILE"C"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ ///\ingroup flat_set
+ /// The base class for all templated flat_set types.
+ //***************************************************************************
+ class flat_set_base
+ {
+ public:
+
+ typedef size_t size_type;
+
+ //*************************************************************************
+ /// Gets the current size of the flat_set.
+ ///\return The current size of the flat_set.
+ //*************************************************************************
+ size_type size() const
+ {
+ return vbase.size();
+ }
+
+ //*************************************************************************
+ /// Checks the 'empty' state of the flat_set.
+ ///\return <b>true</b> if empty.
+ //*************************************************************************
+ bool empty() const
+ {
+ return vbase.empty();
+ }
+
+ //*************************************************************************
+ /// Checks the 'full' state of the flat_set.
+ ///\return <b>true</b> if full.
+ //*************************************************************************
+ bool full() const
+ {
+ return vbase.full();
+ }
+
+ //*************************************************************************
+ /// Returns the capacity of the flat_set.
+ ///\return The capacity of the flat_set.
+ //*************************************************************************
+ size_type capacity() const
+ {
+ return vbase.capacity();
+ }
+
+ //*************************************************************************
+ /// Returns the maximum possible size of the flat_set.
+ ///\return The maximum size of the flat_set.
+ //*************************************************************************
+ size_type max_size() const
+ {
+ return vbase.max_size();
+ }
+
+ //*************************************************************************
+ /// Returns the remaining capacity.
+ ///\return The remaining capacity.
+ //*************************************************************************
+ size_t available() const
+ {
+ return vbase.available();
+ }
+
+ protected:
+
+ //*************************************************************************
+ /// Constructor.
+ //*************************************************************************
+ flat_set_base(vector_base& vbase)
+ : vbase(vbase)
+ {
+ }
+
+ vector_base& vbase;
+ };
+}
+
+#undef ETL_FILE
+
+#endif
diff --git a/lib/etl/private/forward_list_base.h b/lib/etl/private/forward_list_base.h
new file mode 100644
index 0000000..d11fd82
--- /dev/null
+++ b/lib/etl/private/forward_list_base.h
@@ -0,0 +1,264 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_IN_IFORWARD_LIST_H__
+#error This header is a private element of etl::forward_list & etl::iforward_list
+#endif
+
+#ifndef __ETL_LIST_BASE__
+#define __ETL_LIST_BASE__
+
+#include <stddef.h>
+#include "../exception.h"
+#include "../error_handler.h"
+
+#undef ETL_FILE
+#define ETL_FILE "6"
+
+namespace etl
+{
+ //***************************************************************************
+ /// Exception for the forward_list.
+ ///\ingroup forward_list
+ //***************************************************************************
+ class forward_list_exception : public exception
+ {
+ public:
+
+ forward_list_exception(string_type what, string_type file_name, numeric_type line_number)
+ : exception(what, file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// Full exception for the forward_list.
+ ///\ingroup forward_list
+ //***************************************************************************
+ class forward_list_full : public forward_list_exception
+ {
+ public:
+
+ forward_list_full(string_type file_name, numeric_type line_number)
+ : forward_list_exception(ETL_ERROR_TEXT("forward_list:full", ETL_FILE"A"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// Empty exception for the forward_list.
+ ///\ingroup forward_list
+ //***************************************************************************
+ class forward_list_empty : public forward_list_exception
+ {
+ public:
+
+ forward_list_empty(string_type file_name, numeric_type line_number)
+ : forward_list_exception(ETL_ERROR_TEXT("forward_list:empty", ETL_FILE"B"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// Iterator exception for the forward_list.
+ ///\ingroup forward_list
+ //***************************************************************************
+ class forward_list_iterator : public forward_list_exception
+ {
+ public:
+
+ forward_list_iterator(string_type file_name, numeric_type line_number)
+ : forward_list_exception(ETL_ERROR_TEXT("forward_list:iterator", ETL_FILE"C"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// The base class for all forward_lists.
+ ///\ingroup forward_list
+ //***************************************************************************
+ class forward_list_base
+ {
+ protected:
+
+ //*************************************************************************
+ /// The node element in the forward_list.
+ //*************************************************************************
+ struct Node
+ {
+ Node()
+ : next(nullptr)
+ {
+ }
+
+ Node* next;
+ };
+
+ public:
+
+ typedef size_t size_type; ///< The type used for determining the size of forward_list.
+
+ //*************************************************************************
+ /// Gets the size of the forward_list.
+ //*************************************************************************
+ size_type size() const
+ {
+ return current_size;
+ }
+
+ //*************************************************************************
+ /// Gets the maximum possible size of the forward_list.
+ //*************************************************************************
+ size_type max_size() const
+ {
+ return MAX_SIZE;
+ }
+
+ //*************************************************************************
+ /// Checks to see if the forward_list is empty.
+ //*************************************************************************
+ bool empty() const
+ {
+ return current_size == 0;
+ }
+
+ //*************************************************************************
+ /// Checks to see if the forward_list is full.
+ //*************************************************************************
+ bool full() const
+ {
+ return current_size == MAX_SIZE;
+ }
+
+ //*************************************************************************
+ /// Returns the remaining capacity.
+ ///\return The remaining capacity.
+ //*************************************************************************
+ size_t available() const
+ {
+ return max_size() - size();
+ }
+
+ //*************************************************************************
+ /// Reverses the forward_list.
+ //*************************************************************************
+ void reverse()
+ {
+ if (is_trivial_list())
+ {
+ return;
+ }
+
+ Node* p_last = &start_node;
+ Node* p_current = p_last->next;
+ Node* p_next = p_current->next;
+
+ p_current->next = nullptr;
+
+ while (p_next != nullptr)
+ {
+ p_last = p_current;
+ p_current = p_next;
+ p_next = p_current->next;
+
+ p_current->next = p_last;
+ }
+
+ join(&start_node, p_current);
+ }
+
+ protected:
+
+ //*************************************************************************
+ /// The constructor that is called from derived classes.
+ //*************************************************************************
+ forward_list_base(size_type max_size)
+ : next_free(0),
+ current_size(0),
+ MAX_SIZE(max_size)
+ {
+ }
+
+ //*************************************************************************
+ /// Get the head node.
+ //*************************************************************************
+ Node& get_head()
+ {
+ return *start_node.next;
+ }
+
+ //*************************************************************************
+ /// Get the head node.
+ //*************************************************************************
+ const Node& get_head() const
+ {
+ return *start_node.next;
+ }
+
+ //*************************************************************************
+ /// Insert a node.
+ //*************************************************************************
+ void insert_node_after(Node& position, Node& node)
+ {
+ // Connect to the forward_list.
+ node.next = position.next;
+
+ join(&position, &node);
+
+ // One more.
+ ++current_size;
+ }
+
+ //*************************************************************************
+ /// Is the forward_list a trivial length?
+ //*************************************************************************
+ bool is_trivial_list() const
+ {
+ return (size() < 2);
+ }
+
+ //*************************************************************************
+ /// Join two nodes.
+ //*************************************************************************
+ void join(Node* left, Node* right)
+ {
+ left->next = right;
+ }
+
+ Node start_node; ///< The node that acts as the forward_list start.
+ size_type next_free; ///< The index of the next free node.
+ size_type current_size; ///< The number of items in the list.
+ const size_type MAX_SIZE; ///< The maximum size of the forward_list.
+ };
+}
+
+#undef ETL_FILE
+
+#endif
diff --git a/lib/etl/private/ivectorpointer.h b/lib/etl/private/ivectorpointer.h
new file mode 100644
index 0000000..e8bc946
--- /dev/null
+++ b/lib/etl/private/ivectorpointer.h
@@ -0,0 +1,528 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_IVECTOR_POINTER__
+#define __ETL_IVECTOR_POINTER__
+
+#ifndef __ETL_IN_IVECTOR_H__
+#error This header is a private element of etl::ivector
+#endif
+
+#include "pvoidvector.h"
+
+namespace etl
+{
+ //***************************************************************************
+ /// The base class for specifically sized vectors.
+ /// Can be used as a reference type for all vectors containing a specific pointer type.
+ ///\ingroup vector
+ //***************************************************************************
+ template <typename T>
+ class ivector<T*> : public pvoidvector
+ {
+ public:
+
+ typedef T* value_type;
+ typedef T*& reference;
+ typedef const T* const & const_reference;
+ typedef T** pointer;
+ typedef const T* const * const_pointer;
+ typedef T** iterator;
+ typedef const T* const * const_iterator;
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+ typedef size_t size_type;
+ typedef typename std::iterator_traits<iterator>::difference_type difference_type;
+
+ protected:
+
+ typedef value_type parameter_t;
+
+ private:
+
+ typedef pvoidvector base_t;
+
+ public:
+
+ //*********************************************************************
+ /// Returns an iterator to the beginning of the vector.
+ ///\return An iterator to the beginning of the vector.
+ //*********************************************************************
+ iterator begin()
+ {
+ return iterator(base_t::begin());
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the beginning of the vector.
+ ///\return A const iterator to the beginning of the vector.
+ //*********************************************************************
+ const_iterator begin() const
+ {
+ return const_iterator(base_t::begin());
+ }
+
+ //*********************************************************************
+ /// Returns an iterator to the end of the vector.
+ ///\return An iterator to the end of the vector.
+ //*********************************************************************
+ iterator end()
+ {
+ return iterator(base_t::end());
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the end of the vector.
+ ///\return A const iterator to the end of the vector.
+ //*********************************************************************
+ const_iterator end() const
+ {
+ return const_iterator(base_t::end());
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the beginning of the vector.
+ ///\return A const iterator to the beginning of the vector.
+ //*********************************************************************
+ const_iterator cbegin() const
+ {
+ return const_iterator(base_t::cbegin());
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the end of the vector.
+ ///\return A const iterator to the end of the vector.
+ //*********************************************************************
+ const_iterator cend() const
+ {
+ return const_iterator(base_t::cend());
+ }
+
+ //*********************************************************************
+ /// Returns an reverse iterator to the reverse beginning of the vector.
+ ///\return Iterator to the reverse beginning of the vector.
+ //*********************************************************************
+ reverse_iterator rbegin()
+ {
+ return reverse_iterator(iterator(base_t::end()));
+ }
+
+ //*********************************************************************
+ /// Returns a const reverse iterator to the reverse beginning of the vector.
+ ///\return Const iterator to the reverse beginning of the vector.
+ //*********************************************************************
+ const_reverse_iterator rbegin() const
+ {
+ return const_reverse_iterator(const_iterator(base_t::end()));
+ }
+
+ //*********************************************************************
+ /// Returns a reverse iterator to the end + 1 of the vector.
+ ///\return Reverse iterator to the end + 1 of the vector.
+ //*********************************************************************
+ reverse_iterator rend()
+ {
+ return reverse_iterator(iterator(base_t::begin()));
+ }
+
+ //*********************************************************************
+ /// Returns a const reverse iterator to the end + 1 of the vector.
+ ///\return Const reverse iterator to the end + 1 of the vector.
+ //*********************************************************************
+ const_reverse_iterator rend() const
+ {
+ return const_reverse_iterator(const_iterator(base_t::begin()));
+ }
+
+ //*********************************************************************
+ /// Returns a const reverse iterator to the reverse beginning of the vector.
+ ///\return Const reverse iterator to the reverse beginning of the vector.
+ //*********************************************************************
+ const_reverse_iterator crbegin() const
+ {
+ return const_reverse_iterator(const_iterator(base_t::cend()));
+ }
+
+ //*********************************************************************
+ /// Returns a const reverse iterator to the end + 1 of the vector.
+ ///\return Const reverse iterator to the end + 1 of the vector.
+ //*********************************************************************
+ const_reverse_iterator crend() const
+ {
+ return const_reverse_iterator(const_iterator(base_t::cbegin()));
+ }
+
+ //*********************************************************************
+ /// Resizes the vector.
+ /// If asserts or exceptions are enabled and the new size is larger than the
+ /// maximum then a vector_full is thrown.
+ ///\param new_size The new size.
+ //*********************************************************************
+ void resize(size_t new_size)
+ {
+ base_t::resize(new_size);
+ }
+
+ //*********************************************************************
+ /// Resizes the vector.
+ /// If asserts or exceptions are enabled and the new size is larger than the
+ /// maximum then a vector_full is thrown.
+ ///\param new_size The new size.
+ ///\param value The value to fill new elements with. Default = default constructed value.
+ //*********************************************************************
+ void resize(size_t new_size, value_type value)
+ {
+ base_t::resize(new_size, value);
+ }
+
+ //*********************************************************************
+ /// Returns a reference to the value at index 'i'
+ ///\param i The index.
+ ///\return A reference to the value at index 'i'
+ //*********************************************************************
+ reference operator [](size_t i)
+ {
+ return reference(base_t::operator[](i));
+ }
+
+ //*********************************************************************
+ /// Returns a const reference to the value at index 'i'
+ ///\param i The index.
+ ///\return A const reference to the value at index 'i'
+ //*********************************************************************
+ const_reference operator [](size_t i) const
+ {
+ return const_reference(base_t::operator[](i));
+ }
+
+ //*********************************************************************
+ /// Returns a reference to the value at index 'i'
+ /// If asserts or exceptions are enabled, emits an etl::vector_out_of_bounds if the index is out of range.
+ ///\param i The index.
+ ///\return A reference to the value at index 'i'
+ //*********************************************************************
+ reference at(size_t i)
+ {
+ return reference(base_t::at(i));
+ }
+
+ //*********************************************************************
+ /// Returns a const reference to the value at index 'i'
+ /// If asserts or exceptions are enabled, emits an etl::vector_out_of_bounds if the index is out of range.
+ ///\param i The index.
+ ///\return A const reference to the value at index 'i'
+ //*********************************************************************
+ const_reference at(size_t i) const
+ {
+ return const_reference(base_t::at(i));
+ }
+
+ //*********************************************************************
+ /// Returns a reference to the first element.
+ ///\return A reference to the first element.
+ //*********************************************************************
+ reference front()
+ {
+ return reference(base_t::front());
+ }
+
+ //*********************************************************************
+ /// Returns a const reference to the first element.
+ ///\return A const reference to the first element.
+ //*********************************************************************
+ const_reference front() const
+ {
+ return const_reference(base_t::front());
+ }
+
+ //*********************************************************************
+ /// Returns a reference to the last element.
+ ///\return A reference to the last element.
+ //*********************************************************************
+ reference back()
+ {
+ return reference(base_t::back());
+ }
+
+ //*********************************************************************
+ /// Returns a const reference to the last element.
+ ///\return A const reference to the last element.
+ //*********************************************************************
+ const_reference back() const
+ {
+ return const_reference(base_t::back());
+ }
+
+ //*********************************************************************
+ /// Returns a pointer to the beginning of the vector data.
+ ///\return A pointer to the beginning of the vector data.
+ //*********************************************************************
+ pointer data()
+ {
+ return pointer(base_t::data());
+ }
+
+ //*********************************************************************
+ /// Returns a const pointer to the beginning of the vector data.
+ ///\return A const pointer to the beginning of the vector data.
+ //*********************************************************************
+ const_pointer data() const
+ {
+ return const_pointer(base_t::data());
+ }
+
+ //*********************************************************************
+ /// Assigns values to the vector.
+ /// If asserts or exceptions are enabled, emits vector_full if the vector does not have enough free space.
+ /// If asserts or exceptions are enabled, emits vector_iterator if the iterators are reversed.
+ ///\param first The iterator to the first element.
+ ///\param last The iterator to the last element + 1.
+ //*********************************************************************
+ template <typename TIterator>
+ void assign(TIterator first, TIterator last)
+ {
+ base_t::initialise();
+
+ while (first != last)
+ {
+ p_buffer[current_size++] = (void*)*first++;
+ }
+ }
+
+ //*********************************************************************
+ /// Assigns values to the vector.
+ /// If asserts or exceptions are enabled, emits vector_full if the vector does not have enough free space.
+ ///\param n The number of elements to add.
+ ///\param value The value to insert for each element.
+ //*********************************************************************
+ void assign(size_t n, parameter_t value)
+ {
+ base_t::assign(n, value);
+ }
+
+ //*************************************************************************
+ /// Clears the vector.
+ //*************************************************************************
+ void clear()
+ {
+ base_t::clear();
+ }
+
+ //*************************************************************************
+ /// Increases the size of the vector by one, but does not initialise the new element.
+ /// If asserts or exceptions are enabled, throws a vector_full if the vector is already full.
+ //*************************************************************************
+ void push_back()
+ {
+ base_t::push_back();
+ }
+
+ //*********************************************************************
+ /// Inserts a value at the end of the vector.
+ /// If asserts or exceptions are enabled, emits vector_full if the vector is already full.
+ ///\param value The value to add.
+ //*********************************************************************
+ void push_back(parameter_t value)
+ {
+ base_t::push_back(value);
+ }
+
+ //*************************************************************************
+ /// Removes an element from the end of the vector.
+ /// Does nothing if the vector is empty.
+ //*************************************************************************
+ void pop_back()
+ {
+ base_t::pop_back();
+ }
+
+ //*********************************************************************
+ /// Inserts a value to the vector.
+ /// If asserts or exceptions are enabled, emits vector_full if the vector is already full.
+ ///\param position The position to insert before.
+ ///\param value The value to insert.
+ //*********************************************************************
+ iterator insert(iterator position, parameter_t value)
+ {
+ return iterator(base_t::insert(base_t::iterator(position), value));
+ }
+
+ //*********************************************************************
+ /// Inserts 'n' values to the vector.
+ /// If asserts or exceptions are enabled, emits vector_full if the vector does not have enough free space.
+ ///\param position The position to insert before.
+ ///\param n The number of elements to add.
+ ///\param value The value to insert.
+ //*********************************************************************
+ void insert(iterator position, size_t n, parameter_t value)
+ {
+ base_t::insert(base_t::iterator(position), n, value);
+ }
+
+ //*********************************************************************
+ /// Inserts a range of values to the vector.
+ /// If asserts or exceptions are enabled, emits vector_full if the vector does not have enough free space.
+ ///\param position The position to insert before.
+ ///\param first The first element to add.
+ ///\param last The last + 1 element to add.
+ //*********************************************************************
+ template <class TIterator>
+ void insert(iterator position, TIterator first, TIterator last)
+ {
+ base_t::insert(base_t::iterator(position), first, last);
+ }
+
+ //*********************************************************************
+ /// Erases an element.
+ ///\param i_element Iterator to the element.
+ ///\return An iterator pointing to the element that followed the erased element.
+ //*********************************************************************
+ iterator erase(iterator i_element)
+ {
+ return iterator(base_t::erase(base_t::iterator(i_element)));
+ }
+
+ //*********************************************************************
+ /// Erases a range of elements.
+ /// The range includes all the elements between first and last, including the
+ /// element pointed by first, but not the one pointed by last.
+ ///\param first Iterator to the first element.
+ ///\param last Iterator to the last element.
+ ///\return An iterator pointing to the element that followed the erased element.
+ //*********************************************************************
+ iterator erase(iterator first, iterator last)
+ {
+ return iterator(base_t::erase(base_t::iterator(first), base_t::iterator(last)));
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ ivector& operator = (const ivector& rhs)
+ {
+ if (&rhs != this)
+ {
+ assign(rhs.cbegin(), rhs.cend());
+ }
+
+ return *this;
+ }
+
+ protected:
+
+ //*********************************************************************
+ /// Constructor.
+ //*********************************************************************
+ ivector(T** p_buffer, size_t MAX_SIZE)
+ : pvoidvector(reinterpret_cast<void**>(p_buffer), MAX_SIZE)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// Equal operator.
+ ///\param lhs Reference to the first vector.
+ ///\param rhs Reference to the second vector.
+ ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
+ ///\ingroup vector
+ //***************************************************************************
+ template <typename T>
+ bool operator ==(const etl::ivector<T*>& lhs, const etl::ivector<T*>& rhs)
+ {
+ return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin());
+ }
+
+ //***************************************************************************
+ /// Not equal operator.
+ ///\param lhs Reference to the first vector.
+ ///\param rhs Reference to the second vector.
+ ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
+ ///\ingroup vector
+ //***************************************************************************
+ template <typename T>
+ bool operator !=(const etl::ivector<T*>& lhs, const etl::ivector<T*>& rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+ //***************************************************************************
+ /// Less than operator.
+ ///\param lhs Reference to the first vector.
+ ///\param rhs Reference to the second vector.
+ ///\return <b>true</b> if the first vector is lexicographically less than the second, otherwise <b>false</b>
+ ///\ingroup vector
+ //***************************************************************************
+ template <typename T>
+ bool operator <(const etl::ivector<T*>& lhs, const etl::ivector<T*>& rhs)
+ {
+ return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
+ }
+
+ //***************************************************************************
+ /// Greater than operator.
+ ///\param lhs Reference to the first vector.
+ ///\param rhs Reference to the second vector.
+ ///\return <b>true</b> if the first vector is lexicographically greater than the second, otherwise <b>false</b>
+ ///\ingroup vector
+ //***************************************************************************
+ template <typename T>
+ bool operator >(const etl::ivector<T*>& lhs, const etl::ivector<T*>& rhs)
+ {
+ return (rhs < lhs);
+ }
+
+ //***************************************************************************
+ /// Less than or equal operator.
+ ///\param lhs Reference to the first vector.
+ ///\param rhs Reference to the second vector.
+ ///\return <b>true</b> if the first vector is lexigraphically less than or equal to the second, otherwise <b>false</b>
+ ///\ingroup vector
+ //***************************************************************************
+ template <typename T>
+ bool operator <=(const etl::ivector<T*>& lhs, const etl::ivector<T*>& rhs)
+ {
+ return !(lhs > rhs);
+ }
+
+ //***************************************************************************
+ /// Greater than or equal operator.
+ ///\param lhs Reference to the first vector.
+ ///\param rhs Reference to the second vector.
+ ///\return <b>true</b> if the first vector is lexigraphically greater than or equal to the second, otherwise <b>false</b>
+ ///\ingroup vector
+ //***************************************************************************
+ template <typename T>
+ bool operator >=(const etl::ivector<T*>& lhs, const etl::ivector<T*>& rhs)
+ {
+ return !(lhs < rhs);
+ }
+}
+
+#endif
diff --git a/lib/etl/private/list_base.h b/lib/etl/private/list_base.h
new file mode 100644
index 0000000..1b363a4
--- /dev/null
+++ b/lib/etl/private/list_base.h
@@ -0,0 +1,299 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_IN_ILIST_H__
+#error This header is a private element of etl::list & etl::ilist
+#endif
+
+#ifndef __ETL_LIST_BASE__
+#define __ETL_LIST_BASE__
+
+#include <stddef.h>
+#include "../exception.h"
+#include "../error_handler.h"
+
+#undef ETL_FILE
+#define ETL_FILE "7"
+
+namespace etl
+{
+ //***************************************************************************
+ /// Exception for the list.
+ ///\ingroup list
+ //***************************************************************************
+ class list_exception : public exception
+ {
+ public:
+
+ list_exception(string_type what, string_type file_name, numeric_type line_number)
+ : exception(what, file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// Full exception for the list.
+ ///\ingroup list
+ //***************************************************************************
+ class list_full : public list_exception
+ {
+ public:
+
+ list_full(string_type file_name, numeric_type line_number)
+ : list_exception(ETL_ERROR_TEXT("list:full", ETL_FILE"A"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// Empty exception for the list.
+ ///\ingroup list
+ //***************************************************************************
+ class list_empty : public list_exception
+ {
+ public:
+
+ list_empty(string_type file_name, numeric_type line_number)
+ : list_exception(ETL_ERROR_TEXT("list:empty", ETL_FILE"B"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// Iterator exception for the list.
+ ///\ingroup list
+ //***************************************************************************
+ class list_iterator : public list_exception
+ {
+ public:
+
+ list_iterator(string_type file_name, numeric_type line_number)
+ : list_exception(ETL_ERROR_TEXT("list:iterator", ETL_FILE"C"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// Unsorted exception for the list.
+ ///\ingroup list
+ //***************************************************************************
+ class list_unsorted : public list_exception
+ {
+ public:
+
+ list_unsorted(string_type file_name, numeric_type line_number)
+ : list_exception(ETL_ERROR_TEXT("list:unsorted", ETL_FILE"D"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// The base class for all lists.
+ ///\ingroup list
+ //***************************************************************************
+ class list_base
+ {
+ public:
+
+ typedef size_t size_type; ///< The type used for determining the size of list.
+
+ //*************************************************************************
+ /// The node element in the list.
+ //*************************************************************************
+ struct node_t
+ {
+ //***********************************************************************
+ /// Constructor
+ //***********************************************************************
+ node_t()
+ : previous(nullptr),
+ next(nullptr)
+ {
+ }
+
+ //***********************************************************************
+ /// Reverses the previous & next pointers.
+ //***********************************************************************
+ void reverse()
+ {
+ std::swap(previous, next);
+ }
+
+ node_t* previous;
+ node_t* next;
+ };
+
+ //*************************************************************************
+ /// Reverses the list.
+ //*************************************************************************
+ void reverse()
+ {
+ if (is_trivial_list())
+ {
+ return;
+ }
+
+ node_t* p_node = terminal_node.next;
+
+ while (p_node != &terminal_node)
+ {
+ p_node->reverse();
+ p_node = p_node->previous; // Now we've reversed it, we must go to the previous node.
+ }
+
+ // Terminal node.
+ p_node->reverse();
+ }
+
+ //*************************************************************************
+ /// Gets the size of the list.
+ //*************************************************************************
+ size_type size() const
+ {
+ return current_size;
+ }
+
+ //*************************************************************************
+ /// Gets the maximum possible size of the list.
+ //*************************************************************************
+ size_type max_size() const
+ {
+ return MAX_SIZE;
+ }
+
+ //*************************************************************************
+ /// Checks to see if the list is empty.
+ //*************************************************************************
+ bool empty() const
+ {
+ return current_size == 0;
+ }
+
+ //*************************************************************************
+ /// Checks to see if the list is full.
+ //*************************************************************************
+ bool full() const
+ {
+ return current_size == MAX_SIZE;
+ }
+
+ //*************************************************************************
+ /// Returns the remaining capacity.
+ ///\return The remaining capacity.
+ //*************************************************************************
+ size_t available() const
+ {
+ return max_size() - size();
+ }
+
+ protected:
+
+ //*************************************************************************
+ /// Get the head node.
+ //*************************************************************************
+ node_t& get_head()
+ {
+ return *terminal_node.next;
+ }
+
+ //*************************************************************************
+ /// Get the head node.
+ //*************************************************************************
+ const node_t& get_head() const
+ {
+ return *terminal_node.next;
+ }
+
+ //*************************************************************************
+ /// Get the tail node.
+ //*************************************************************************
+ node_t& get_tail()
+ {
+ return *terminal_node.previous;
+ }
+
+ //*************************************************************************
+ /// Get the tail node.
+ //*************************************************************************
+ const node_t& get_tail() const
+ {
+ return *terminal_node.previous;
+ }
+
+ //*************************************************************************
+ /// Insert a node before 'position'.
+ //*************************************************************************
+ void insert_node(node_t& position, node_t& node)
+ {
+ // Connect to the list.
+ join(*position.previous, node);
+ join(node, position);
+
+ // One more.
+ ++current_size;
+ }
+
+ //*************************************************************************
+ /// Is the list a trivial length?
+ //*************************************************************************
+ bool is_trivial_list() const
+ {
+ return (size() < 2);
+ }
+
+ //*************************************************************************
+ /// Join two nodes.
+ //*************************************************************************
+ void join(node_t& left, node_t& right)
+ {
+ left.next = &right;
+ right.previous = &left;
+ }
+
+ //*************************************************************************
+ /// The constructor that is called from derived classes.
+ //*************************************************************************
+ list_base(size_type max_size)
+ : current_size(0),
+ MAX_SIZE(max_size)
+
+ {
+ }
+
+
+ node_t terminal_node; ///< The node that acts as the list start and end.
+ size_type current_size; ///< The number of the used nodes.
+ const size_type MAX_SIZE; ///< The maximum size of the list.
+ };
+}
+
+#undef ETL_FILE
+
+#endif
diff --git a/lib/etl/private/map_base.h b/lib/etl/private/map_base.h
new file mode 100644
index 0000000..539554a
--- /dev/null
+++ b/lib/etl/private/map_base.h
@@ -0,0 +1,427 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove, rlindeman
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#if !defined(__ETL_IN_IMAP_H__)
+#error This header is a private element of etl::map & etl::imap
+#endif
+
+#ifndef __ETL_MAP_BASE__
+#define __ETL_MAP_BASE__
+
+#include <stddef.h>
+#include "../exception.h"
+#include "../error_handler.h"
+
+#undef ETL_FILE
+#define ETL_FILE "8"
+
+namespace etl
+{
+ //***************************************************************************
+ /// Exception for the map.
+ ///\ingroup map
+ //***************************************************************************
+ class map_exception : public exception
+ {
+ public:
+
+ map_exception(string_type what, string_type file_name, numeric_type line_number)
+ : exception(what, file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// Full exception for the map.
+ ///\ingroup map
+ //***************************************************************************
+ class map_full : public map_exception
+ {
+ public:
+
+ map_full(string_type file_name, numeric_type line_number)
+ : map_exception("map:full", file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// Map out of bounds exception.
+ ///\ingroup map
+ //***************************************************************************
+ class map_out_of_bounds : public map_exception
+ {
+ public:
+
+ map_out_of_bounds(string_type file_name, numeric_type line_number)
+ : map_exception("map:bounds", file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// Iterator exception for the map.
+ ///\ingroup map
+ //***************************************************************************
+ class map_iterator : public map_exception
+ {
+ public:
+
+ map_iterator(string_type file_name, numeric_type line_number)
+ : map_exception("map:iterator", file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// The base class for all maps.
+ ///\ingroup map
+ //***************************************************************************
+ class map_base
+ {
+ public:
+
+ typedef size_t size_type; ///< The type used for determining the size of map.
+
+ //*************************************************************************
+ /// Gets the size of the map.
+ //*************************************************************************
+ size_type size() const
+ {
+ return current_size;
+ }
+
+ //*************************************************************************
+ /// Gets the maximum possible size of the map.
+ //*************************************************************************
+ size_type max_size() const
+ {
+ return MAX_SIZE;
+ }
+
+ //*************************************************************************
+ /// Checks to see if the map is empty.
+ //*************************************************************************
+ bool empty() const
+ {
+ return current_size == 0;
+ }
+
+ //*************************************************************************
+ /// Checks to see if the map is full.
+ //*************************************************************************
+ bool full() const
+ {
+ return current_size == MAX_SIZE;
+ }
+
+ //*************************************************************************
+ /// Returns the capacity of the vector.
+ ///\return The capacity of the vector.
+ //*************************************************************************
+ size_type capacity() const
+ {
+ return MAX_SIZE;
+ }
+
+ //*************************************************************************
+ /// Returns the remaining capacity.
+ ///\return The remaining capacity.
+ //*************************************************************************
+ size_t available() const
+ {
+ return max_size() - size();
+ }
+
+ protected:
+
+ enum
+ {
+ kLeft = 0,
+ kRight = 1,
+ kNeither = 2
+ };
+
+ //*************************************************************************
+ /// The node element in the map.
+ //*************************************************************************
+ struct Node
+ {
+ //***********************************************************************
+ /// Constructor
+ //***********************************************************************
+ Node() :
+ weight(kNeither),
+ dir(kNeither)
+ {
+ }
+
+ //***********************************************************************
+ /// Marks the node as a leaf.
+ //***********************************************************************
+ void mark_as_leaf()
+ {
+ weight = kNeither;
+ dir = kNeither;
+ children[0] = nullptr;
+ children[1] = nullptr;
+ }
+
+ Node* children[2];
+ uint8_t weight;
+ uint8_t dir;
+ };
+
+ //*************************************************************************
+ /// The constructor that is called from derived classes.
+ //*************************************************************************
+ map_base(size_type max_size)
+ : current_size(0)
+ , MAX_SIZE(max_size)
+ , root_node(nullptr)
+
+ {
+ }
+
+ //*************************************************************************
+ /// Balance the critical node at the position provided as needed
+ //*************************************************************************
+ void balance_node(Node*& critical_node)
+ {
+ // Step 1: Update weights for all children of the critical node up to the
+ // newly inserted node. This step is costly (in terms of traversing nodes
+ // multiple times during insertion) but doesn't require as much recursion
+ Node* weight_node = critical_node->children[critical_node->dir];
+ while (weight_node)
+ {
+ // Keep going until we reach a terminal node (dir == kNeither)
+ if (kNeither != weight_node->dir)
+ {
+ // Does this insert balance the previous weight factor value?
+ if (weight_node->weight == 1 - weight_node->dir)
+ {
+ weight_node->weight = kNeither;
+ }
+ else
+ {
+ weight_node->weight = weight_node->dir;
+ }
+
+ // Update weight factor node to point to next node
+ weight_node = weight_node->children[weight_node->dir];
+ }
+ else
+ {
+ // Stop loop, terminal node found
+ break;
+ }
+ } // while(weight_node)
+
+ // Step 2: Update weight for critical_node or rotate tree to balance node
+ if (kNeither == critical_node->weight)
+ {
+ critical_node->weight = critical_node->dir;
+ }
+ // If direction is different than weight, then it will now be balanced
+ else if (critical_node->dir != critical_node->weight)
+ {
+ critical_node->weight = kNeither;
+ }
+ // Rotate is required to balance the tree at the critical node
+ else
+ {
+ // If critical node matches child node direction then perform a two
+ // node rotate in the direction of the critical node
+ if (critical_node->weight == critical_node->children[critical_node->dir]->dir)
+ {
+ rotate_2node(critical_node, critical_node->dir);
+ }
+ // Otherwise perform a three node rotation in the direction of the
+ // critical node
+ else
+ {
+ rotate_3node(critical_node, critical_node->dir,
+ critical_node->children[critical_node->dir]->children[1 - critical_node->dir]->dir);
+ }
+ }
+ }
+
+ //*************************************************************************
+ /// Rotate two nodes at the position provided the to balance the tree
+ //*************************************************************************
+ void rotate_2node(Node*& position, uint8_t dir)
+ {
+ // A C A B
+ // B C -> A E OR B C -> D A
+ // D E B D D E E C
+ // C (new position) becomes the root
+ // A (position) takes ownership of D as its children[kRight] child
+ // C (new position) takes ownership of A as its left child
+ // OR
+ // B (new position) becomes the root
+ // A (position) takes ownership of E as its left child
+ // B (new position) takes ownership of A as its right child
+
+ // Capture new root
+ Node* new_root = position->children[dir];
+ // Replace position's previous child with new root's other child
+ position->children[dir] = new_root->children[1 - dir];
+ // New root now becomes parent of current position
+ new_root->children[1 - dir] = position;
+ // Clear weight factor from current position
+ position->weight = kNeither;
+ // Newly detached right now becomes current position
+ position = new_root;
+ // Clear weight factor from new root
+ position->weight = kNeither;
+ }
+
+ //*************************************************************************
+ /// Rotate three nodes at the position provided the to balance the tree
+ //*************************************************************************
+ void rotate_3node(Node*& position, uint8_t dir, uint8_t third)
+ {
+ // __A__ __E__ __A__ __D__
+ // _B_ C -> B A OR B _C_ -> A C
+ // D E D F G C D E B F G E
+ // F G F G
+ // E (new position) becomes the root
+ // B (position) takes ownership of F as its left child
+ // A takes ownership of G as its right child
+ // OR
+ // D (new position) becomes the root
+ // A (position) takes ownership of F as its right child
+ // C takes ownership of G as its left child
+
+ // Capture new root (either E or D depending on dir)
+ Node* new_root = position->children[dir]->children[1 - dir];
+ // Set weight factor for B or C based on F or G existing and being a different than dir
+ position->children[dir]->weight = third != kNeither && third != dir ? dir : kNeither;
+
+ // Detach new root from its tree (replace with new roots child)
+ position->children[dir]->children[1 - dir] =
+ new_root->children[dir];
+ // Attach current left tree to new root
+ new_root->children[dir] = position->children[dir];
+ // Set weight factor for A based on F or G
+ position->weight = third != kNeither && third == dir ? 1 - dir : kNeither;
+
+ // Move new root's right tree to current roots left tree
+ position->children[dir] = new_root->children[1 - dir];
+ // Attach current root to new roots right tree
+ new_root->children[1 - dir] = position;
+ // Replace current position with new root
+ position = new_root;
+ // Clear weight factor for new current position
+ position->weight = kNeither;
+ }
+
+ //*************************************************************************
+ /// Find the node whose key would go before all the other keys from the
+ /// position provided
+ //*************************************************************************
+ Node* find_limit_node(Node* position, const int8_t dir) const
+ {
+ // Something at this position and in the direction specified? keep going
+ Node* limit_node = position;
+ while (limit_node && limit_node->children[dir])
+ {
+ limit_node = limit_node->children[dir];
+ }
+
+ // Return the limit node position found
+ return limit_node;
+ }
+
+ //*************************************************************************
+ /// Find the node whose key would go before all the other keys from the
+ /// position provided
+ //*************************************************************************
+ const Node* find_limit_node(const Node* position, const int8_t dir) const
+ {
+ // Something at this position and in the direction specified? keep going
+ const Node* limit_node = position;
+ while (limit_node && limit_node->children[dir])
+ {
+ limit_node = limit_node->children[dir];
+ }
+
+ // Return the limit node position found
+ return limit_node;
+ }
+
+ //*************************************************************************
+ /// Attach the provided node to the position provided
+ //*************************************************************************
+ void attach_node(Node*& position, Node& node)
+ {
+ // Mark new node as leaf on attach to tree at position provided
+ node.mark_as_leaf();
+
+ // Add the node here
+ position = &node;
+
+ // One more.
+ ++current_size;
+ }
+
+ //*************************************************************************
+ /// Detach the node at the position provided
+ //*************************************************************************
+ void detach_node(Node*& position, Node*& replacement)
+ {
+ // Make temporary copy of actual nodes involved because we might lose
+ // their references in the process (e.g. position is the same as
+ // replacement or replacement is a child of position)
+ Node* detached = position;
+ Node* swap = replacement;
+
+ // Update current position to point to swap (replacement) node first
+ position = swap;
+
+ // Update replacement node to point to child in opposite direction
+ // otherwise we might lose the other child of the swap node
+ replacement = swap->children[1 - swap->dir];
+
+ // Point swap node to detached node's children and weight
+ swap->children[kLeft] = detached->children[kLeft];
+ swap->children[kRight] = detached->children[kRight];
+ swap->weight = detached->weight;
+ }
+
+ size_type current_size; ///< The number of the used nodes.
+ const size_type MAX_SIZE; ///< The maximum size of the map.
+ Node* root_node; ///< The node that acts as the map root.
+ };
+}
+
+#undef ETL_FILE
+
+#endif
diff --git a/lib/etl/private/multimap_base.h b/lib/etl/private/multimap_base.h
new file mode 100644
index 0000000..02b85f9
--- /dev/null
+++ b/lib/etl/private/multimap_base.h
@@ -0,0 +1,586 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove, rlindeman
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#if !defined(__ETL_IN_IMULTIMAP_H__)
+#error This header is a private element of etl::multimap & etl::imultimap
+#endif
+
+#ifndef __ETL_MULTIMAP_BASE__
+#define __ETL_MULTIMAP_BASE__
+
+#include <stddef.h>
+#include "../exception.h"
+#include "../error_handler.h"
+
+#undef ETL_FILE
+#define ETL_FILE "9"
+
+namespace etl
+{
+ //***************************************************************************
+ /// Exception for the map.
+ ///\ingroup map
+ //***************************************************************************
+ class multimap_exception : public exception
+ {
+ public:
+
+ multimap_exception(string_type what, string_type file_name, numeric_type line_number)
+ : exception(what, file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// Full exception for the map.
+ ///\ingroup map
+ //***************************************************************************
+ class multimap_full : public multimap_exception
+ {
+ public:
+
+ multimap_full(string_type file_name, numeric_type line_number)
+ : multimap_exception("multimap:full", file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// Map out of bounds exception.
+ ///\ingroup map
+ //***************************************************************************
+ class multimap_out_of_bounds : public multimap_exception
+ {
+ public:
+
+ multimap_out_of_bounds(string_type file_name, numeric_type line_number)
+ : multimap_exception("multimap:bounds", file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// Iterator exception for the map.
+ ///\ingroup map
+ //***************************************************************************
+ class multimap_iterator : public multimap_exception
+ {
+ public:
+
+ multimap_iterator(string_type file_name, numeric_type line_number)
+ : multimap_exception("multimap:iterator", file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// The base class for all maps.
+ ///\ingroup map
+ //***************************************************************************
+ class multimap_base
+ {
+ public:
+
+ typedef size_t size_type; ///< The type used for determining the size of map.
+
+ //*************************************************************************
+ /// Gets the size of the map.
+ //*************************************************************************
+ size_type size() const
+ {
+ return current_size;
+ }
+
+ //*************************************************************************
+ /// Gets the maximum possible size of the map.
+ //*************************************************************************
+ size_type max_size() const
+ {
+ return MAX_SIZE;
+ }
+
+ //*************************************************************************
+ /// Checks to see if the map is empty.
+ //*************************************************************************
+ bool empty() const
+ {
+ return current_size == 0;
+ }
+
+ //*************************************************************************
+ /// Checks to see if the map is full.
+ //*************************************************************************
+ bool full() const
+ {
+ return current_size == MAX_SIZE;
+ }
+
+ //*************************************************************************
+ /// Returns the capacity of the vector.
+ ///\return The capacity of the vector.
+ //*************************************************************************
+ size_type capacity() const
+ {
+ return MAX_SIZE;
+ }
+
+ //*************************************************************************
+ /// Returns the remaining capacity.
+ ///\return The remaining capacity.
+ //*************************************************************************
+ size_t available() const
+ {
+ return max_size() - size();
+ }
+
+ protected:
+
+ static const uint8_t kLeft = 0;
+ static const uint8_t kRight = 1;
+ static const uint8_t kNeither = 2;
+
+ //*************************************************************************
+ /// The node element in the multimap.
+ //*************************************************************************
+ struct Node
+ {
+ //***********************************************************************
+ /// Constructor
+ //***********************************************************************
+ Node() :
+ weight(kNeither),
+ dir(kNeither)
+ {
+ }
+
+ //***********************************************************************
+ /// Marks the node as a leaf.
+ //***********************************************************************
+ void mark_as_leaf()
+ {
+ weight = kNeither;
+ dir = kNeither;
+ parent = nullptr;
+ children[0] = nullptr;
+ children[1] = nullptr;
+ }
+
+ Node* parent;
+ Node* children[2];
+ uint8_t weight;
+ uint8_t dir;
+ };
+
+ //*************************************************************************
+ /// The constructor that is called from derived classes.
+ //*************************************************************************
+ multimap_base(size_type max_size)
+ : current_size(0)
+ , MAX_SIZE(max_size)
+ , root_node(nullptr)
+
+ {
+ }
+
+ //*************************************************************************
+ /// Balance the critical node at the position provided as needed
+ //*************************************************************************
+ void balance_node(Node*& critical_node)
+ {
+ // Step 1: Update weights for all children of the critical node up to the
+ // newly inserted node. This step is costly (in terms of traversing nodes
+ // multiple times during insertion) but doesn't require as much recursion
+ Node* weight_node = critical_node->children[critical_node->dir];
+ while (weight_node)
+ {
+ // Keep going until we reach a terminal node (dir == kNeither)
+ if (kNeither != weight_node->dir)
+ {
+ // Does this insert balance the previous weight factor value?
+ if (weight_node->weight == 1 - weight_node->dir)
+ {
+ weight_node->weight = kNeither;
+ }
+ else
+ {
+ weight_node->weight = weight_node->dir;
+ }
+
+ // Update weight factor node to point to next node
+ weight_node = weight_node->children[weight_node->dir];
+ }
+ else
+ {
+ // Stop loop, terminal node found
+ break;
+ }
+ } // while(weight_node)
+
+ // Step 2: Update weight for critical_node or rotate tree to balance node
+ if (kNeither == critical_node->weight)
+ {
+ critical_node->weight = critical_node->dir;
+ }
+ // If direction is different than weight, then it will now be balanced
+ else if (critical_node->dir != critical_node->weight)
+ {
+ critical_node->weight = kNeither;
+ }
+ // Rotate is required to balance the tree at the critical node
+ else
+ {
+ // If critical node matches child node direction then perform a two
+ // node rotate in the direction of the critical node
+ if (critical_node->weight == critical_node->children[critical_node->dir]->dir)
+ {
+ rotate_2node(critical_node, critical_node->dir);
+ }
+ // Otherwise perform a three node rotation in the direction of the
+ // critical node
+ else
+ {
+ rotate_3node(critical_node, critical_node->dir,
+ critical_node->children[critical_node->dir]->children[1 - critical_node->dir]->dir);
+ }
+ }
+ }
+
+ //*************************************************************************
+ /// Rotate two nodes at the position provided the to balance the tree
+ //*************************************************************************
+ void rotate_2node(Node*& position, uint8_t dir)
+ {
+ // A C A B
+ // B C -> A E OR B C -> D A
+ // D E B D D E E C
+ // C (new position) becomes the root
+ // A (position) takes ownership of D as its children[kRight] child
+ // C (new position) takes ownership of A as its left child
+ // OR
+ // B (new position) becomes the root
+ // A (position) takes ownership of E as its left child
+ // B (new position) takes ownership of A as its right child
+
+ // Capture new root (either B or C depending on dir) and its parent
+ Node* new_root = position->children[dir];
+
+ // Replace position's previous child with new root's other child
+ position->children[dir] = new_root->children[1 - dir];
+ // Update new root's other child parent pointer
+ if (position->children[dir])
+ {
+ position->children[dir]->parent = position;
+ }
+
+ // New root's parent becomes current position's parent
+ new_root->parent = position->parent;
+ new_root->children[1 - dir] = position;
+ new_root->dir = 1 - dir;
+
+ // Clear weight factor from current position
+ position->weight = kNeither;
+ // Position's parent becomes new_root
+ position->parent = new_root;
+ position = new_root;
+ // Clear weight factor from new root
+ position->weight = kNeither;
+ }
+
+ //*************************************************************************
+ /// Rotate three nodes at the position provided the to balance the tree
+ //*************************************************************************
+ void rotate_3node(Node*& position, uint8_t dir, uint8_t third)
+ {
+ // __A__ __E__ __A__ __D__
+ // _B_ C -> B A OR B _C_ -> A C
+ // D E D F G C D E B F G E
+ // F G F G
+ // E (new position) becomes the root
+ // B (position) takes ownership of F as its left child
+ // A takes ownership of G as its right child
+ // OR
+ // D (new position) becomes the root
+ // A (position) takes ownership of F as its right child
+ // C takes ownership of G as its left child
+
+ // Capture new root (either E or D depending on dir)
+ Node* new_root = position->children[dir]->children[1 - dir];
+ // Set weight factor for B or C based on F or G existing and being a different than dir
+ position->children[dir]->weight = third != kNeither && third != dir ? dir : kNeither;
+
+ // Detach new root from its tree (replace with new roots child)
+ position->children[dir]->children[1 - dir] = new_root->children[dir];
+ // Update new roots child parent pointer
+ if (new_root->children[dir])
+ {
+ new_root->children[dir]->parent = position->children[dir];
+ }
+
+ // Attach current left tree to new root and update its parent
+ new_root->children[dir] = position->children[dir];
+ position->children[dir]->parent = new_root;
+
+ // Set weight factor for A based on F or G
+ position->weight = third != kNeither && third == dir ? 1 - dir : kNeither;
+
+ // Move new root's right tree to current roots left tree
+ position->children[dir] = new_root->children[1 - dir];
+ if (new_root->children[1 - dir])
+ {
+ new_root->children[1 - dir]->parent = position;
+ }
+
+ // Attach current root to new roots right tree and assume its parent
+ new_root->parent = position->parent;
+ new_root->children[1 - dir] = position;
+ new_root->dir = 1 - dir;
+
+ // Update current position's parent and replace with new root
+ position->parent = new_root;
+ position = new_root;
+ // Clear weight factor for new current position
+ position->weight = kNeither;
+ }
+
+ //*************************************************************************
+ /// Find the next node in sequence from the node provided
+ //*************************************************************************
+ void next_node(Node*& position) const
+ {
+ if (position)
+ {
+ // Is there a tree on the right? then find the minimum of that tree
+ if (position->children[kRight])
+ {
+ // Return minimum node found
+ position = find_limit_node(position->children[kRight], kLeft);
+ }
+ // Otherwise find the parent of this node
+ else
+ {
+ // Start with current position as parent
+ Node* parent = position;
+ do {
+ // Update current position as previous parent
+ position = parent;
+ // Find parent of current position
+ parent = position->parent; // find_parent_node(root_node, position);
+ // Repeat while previous position was on right side of parent tree
+ } while (parent && parent->children[kRight] == position);
+
+ // Set parent node as the next position
+ position = parent;
+ }
+ }
+ }
+
+ //*************************************************************************
+ /// Find the next node in sequence from the node provided
+ //*************************************************************************
+ void next_node(const Node*& position) const
+ {
+ if (position)
+ {
+ // Is there a tree on the right? then find the minimum of that tree
+ if (position->children[kRight])
+ {
+ // Return minimum node found
+ position = find_limit_node(position->children[kRight], kLeft);
+ }
+ // Otherwise find the parent of this node
+ else
+ {
+ // Start with current position as parent
+ const Node* parent = position;
+ do {
+ // Update current position as previous parent
+ position = parent;
+ // Find parent of current position
+ parent = position->parent;
+ // Repeat while previous position was on right side of parent tree
+ } while (parent && parent->children[kRight] == position);
+
+ // Set parent node as the next position
+ position = parent;
+ }
+ }
+ }
+
+ //*************************************************************************
+ /// Find the previous node in sequence from the node provided
+ //*************************************************************************
+ void prev_node(Node*& position) const
+ {
+ // If starting at the terminal end, the previous node is the maximum node
+ // from the root
+ if (!position)
+ {
+ position = find_limit_node(root_node, kRight);
+ }
+ else
+ {
+ // Is there a tree on the left? then find the maximum of that tree
+ if (position->children[kLeft])
+ {
+ // Return maximum node found
+ position = find_limit_node(position->children[kLeft], kRight);
+ }
+ // Otherwise find the parent of this node
+ else
+ {
+ // Start with current position as parent
+ Node* parent = position;
+ do {
+ // Update current position as previous parent
+ position = parent;
+ // Find parent of current position
+ parent = position->parent;
+ // Repeat while previous position was on left side of parent tree
+ } while (parent && parent->children[kLeft] == position);
+
+ // Set parent node as the next position
+ position = parent;
+ }
+ }
+ }
+
+ //*************************************************************************
+ /// Find the previous node in sequence from the node provided
+ //*************************************************************************
+ void prev_node(const Node*& position) const
+ {
+ // If starting at the terminal end, the previous node is the maximum node
+ // from the root
+ if (!position)
+ {
+ position = find_limit_node(root_node, kRight);
+ }
+ else
+ {
+ // Is there a tree on the left? then find the maximum of that tree
+ if (position->children[kLeft])
+ {
+ // Return maximum node found
+ position = find_limit_node(position->children[kLeft], kRight);
+ }
+ // Otherwise find the parent of this node
+ else
+ {
+ // Start with current position as parent
+ const Node* parent = position;
+ do {
+ // Update current position as previous parent
+ position = parent;
+ // Find parent of current position
+ parent = position->parent;
+ // Repeat while previous position was on left side of parent tree
+ } while (parent && parent->children[kLeft] == position);
+
+ // Set parent node as the next position
+ position = parent;
+ }
+ }
+ }
+
+ //*************************************************************************
+ /// Find the node whose key would go before all the other keys from the
+ /// position provided
+ //*************************************************************************
+ Node* find_limit_node(Node* position, const int8_t dir) const
+ {
+ // Something at this position and in the direction specified? keep going
+ Node* limit_node = position;
+ while (limit_node && limit_node->children[dir])
+ {
+ limit_node = limit_node->children[dir];
+ }
+
+ // Return the limit node position found
+ return limit_node;
+ }
+
+ //*************************************************************************
+ /// Attach the provided node to the position provided
+ //*************************************************************************
+ void attach_node(Node* parent, Node*& position, Node& node)
+ {
+ // Mark new node as leaf on attach to tree at position provided
+ node.mark_as_leaf();
+
+ // Keep track of this node's parent
+ node.parent = parent;
+
+ // Add the node here
+ position = &node;
+
+ // One more.
+ ++current_size;
+ }
+
+ //*************************************************************************
+ /// Detach the node at the position provided
+ //*************************************************************************
+ void detach_node(Node*& position, Node*& replacement)
+ {
+ // Make temporary copy of actual nodes involved because we might lose
+ // their references in the process (e.g. position is the same as
+ // replacement or replacement is a child of position)
+ Node* detached = position;
+ Node* swap = replacement;
+
+ // Update current position to point to swap (replacement) node first
+ position = swap;
+
+ // Update replacement node to point to child in opposite direction
+ // otherwise we might lose the other child of the swap node
+ replacement = swap->children[1 - swap->dir];
+
+ // Point swap node to detached node's parent, children and weight
+ swap->parent = detached->parent;
+ swap->children[kLeft] = detached->children[kLeft];
+ swap->children[kRight] = detached->children[kRight];
+ if (swap->children[kLeft])
+ {
+ swap->children[kLeft]->parent = swap;
+ }
+ if (swap->children[kRight])
+ {
+ swap->children[kRight]->parent = swap;
+ }
+ swap->weight = detached->weight;
+ }
+
+ size_type current_size; ///< The number of the used nodes.
+ const size_type MAX_SIZE; ///< The maximum size of the map.
+ Node* root_node; ///< The node that acts as the multimap root.
+ };
+}
+
+#endif
diff --git a/lib/etl/private/multiset_base.h b/lib/etl/private/multiset_base.h
new file mode 100644
index 0000000..5b9a1d3
--- /dev/null
+++ b/lib/etl/private/multiset_base.h
@@ -0,0 +1,587 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2015 jwellbelove, rlindeman
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#if !defined(__ETL_IN_IMULTISET_H__)
+#error This header is a private element of etl::multiset & etl::imultiset
+#endif
+
+#ifndef __ETL_MULTISET_BASE__
+#define __ETL_MULTISET_BASE__
+
+#include <stddef.h>
+#include "../exception.h"
+#include "../error_handler.h"
+
+#undef ETL_FILE
+#define ETL_FILE "10"
+
+namespace etl
+{
+ //***************************************************************************
+ /// Exception for the set.
+ ///\ingroup set
+ //***************************************************************************
+ class multiset_exception : public exception
+ {
+ public:
+
+ multiset_exception(string_type what, string_type file_name, numeric_type line_number)
+ : exception(what, file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// Full exception for the set.
+ ///\ingroup set
+ //***************************************************************************
+ class multiset_full : public multiset_exception
+ {
+ public:
+
+ multiset_full(string_type file_name, numeric_type line_number)
+ : multiset_exception(ETL_ERROR_TEXT("multiset:full", ETL_FILE"A"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// Map out of bounds exception.
+ ///\ingroup set
+ //***************************************************************************
+ class multiset_out_of_bounds : public multiset_exception
+ {
+ public:
+
+ multiset_out_of_bounds(string_type file_name, numeric_type line_number)
+ : multiset_exception(ETL_ERROR_TEXT("multiset:bounds", ETL_FILE"B"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// Iterator exception for the set.
+ ///\ingroup set
+ //***************************************************************************
+ class multiset_iterator : public multiset_exception
+ {
+ public:
+
+ multiset_iterator(string_type file_name, numeric_type line_number)
+ : multiset_exception(ETL_ERROR_TEXT("multiset:iterator", ETL_FILE"C"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// The base class for all sets.
+ ///\ingroup set
+ //***************************************************************************
+ class multiset_base
+ {
+ public:
+
+ typedef size_t size_type; ///< The type used for determining the size of set.
+
+ //*************************************************************************
+ /// Gets the size of the set.
+ //*************************************************************************
+ size_type size() const
+ {
+ return current_size;
+ }
+
+ //*************************************************************************
+ /// Gets the maximum possible size of the set.
+ //*************************************************************************
+ size_type max_size() const
+ {
+ return MAX_SIZE;
+ }
+
+ //*************************************************************************
+ /// Checks to see if the set is empty.
+ //*************************************************************************
+ bool empty() const
+ {
+ return current_size == 0;
+ }
+
+ //*************************************************************************
+ /// Checks to see if the set is full.
+ //*************************************************************************
+ bool full() const
+ {
+ return current_size == MAX_SIZE;
+ }
+
+ //*************************************************************************
+ /// Returns the capacity of the vector.
+ ///\return The capacity of the vector.
+ //*************************************************************************
+ size_type capacity() const
+ {
+ return MAX_SIZE;
+ }
+
+ //*************************************************************************
+ /// Returns the remaining capacity.
+ ///\return The remaining capacity.
+ //*************************************************************************
+ size_t available() const
+ {
+ return max_size() - size();
+ }
+
+ protected:
+
+ static const uint8_t kLeft = 0;
+ static const uint8_t kRight = 1;
+ static const uint8_t kNeither = 2;
+
+ //*************************************************************************
+ /// The node element in the multiset.
+ //*************************************************************************
+ struct Node
+ {
+ //***********************************************************************
+ /// Constructor
+ //***********************************************************************
+ Node() :
+ weight(kNeither),
+ dir(kNeither)
+ {
+ }
+
+ //***********************************************************************
+ /// Marks the node as a leaf.
+ //***********************************************************************
+ void mark_as_leaf()
+ {
+ weight = kNeither;
+ dir = kNeither;
+ parent = nullptr;
+ children[0] = nullptr;
+ children[1] = nullptr;
+ }
+
+ Node* parent;
+ Node* children[2];
+ uint8_t weight;
+ uint8_t dir;
+ };
+
+ //*************************************************************************
+ /// The constructor that is called from derived classes.
+ //*************************************************************************
+ multiset_base(size_type max_size)
+ : current_size(0)
+ , MAX_SIZE(max_size)
+ , root_node(nullptr)
+ {
+ }
+
+ //*************************************************************************
+ /// Attach the provided node to the position provided
+ //*************************************************************************
+ void attach_node(Node* parent, Node*& position, Node& node)
+ {
+ // Mark new node as leaf on attach to tree at position provided
+ node.mark_as_leaf();
+
+ // Keep track of this node's parent
+ node.parent = parent;
+
+ // Add the node here
+ position = &node;
+
+ // One more.
+ ++current_size;
+ }
+
+ //*************************************************************************
+ /// Detach the node at the position provided
+ //*************************************************************************
+ void detach_node(Node*& position, Node*& replacement)
+ {
+ // Make temporary copy of actual nodes involved because we might lose
+ // their references in the process (e.g. position is the same as
+ // replacement or replacement is a child of position)
+ Node* detached = position;
+ Node* swap = replacement;
+
+ // Update current position to point to swap (replacement) node first
+ position = swap;
+
+ // Update replacement node to point to child in opposite direction
+ // otherwise we might lose the other child of the swap node
+ replacement = swap->children[1 - swap->dir];
+
+ // Point swap node to detached node's parent, children and weight
+ swap->parent = detached->parent;
+ swap->children[kLeft] = detached->children[kLeft];
+ swap->children[kRight] = detached->children[kRight];
+ if (swap->children[kLeft])
+ {
+ swap->children[kLeft]->parent = swap;
+ }
+ if (swap->children[kRight])
+ {
+ swap->children[kRight]->parent = swap;
+ }
+ swap->weight = detached->weight;
+ }
+
+ //*************************************************************************
+ /// Balance the critical node at the position provided as needed
+ //*************************************************************************
+ void balance_node(Node*& critical_node)
+ {
+ // Step 1: Update weights for all children of the critical node up to the
+ // newly inserted node. This step is costly (in terms of traversing nodes
+ // multiple times during insertion) but doesn't require as much recursion
+ Node* weight_node = critical_node->children[critical_node->dir];
+ while (weight_node)
+ {
+ // Keep going until we reach a terminal node (dir == kNeither)
+ if (kNeither != weight_node->dir)
+ {
+ // Does this insert balance the previous weight factor value?
+ if (weight_node->weight == 1 - weight_node->dir)
+ {
+ weight_node->weight = kNeither;
+ }
+ else
+ {
+ weight_node->weight = weight_node->dir;
+ }
+
+ // Update weight factor node to point to next node
+ weight_node = weight_node->children[weight_node->dir];
+ }
+ else
+ {
+ // Stop loop, terminal node found
+ break;
+ }
+ } // while(weight_node)
+
+ // Step 2: Update weight for critical_node or rotate tree to balance node
+ if (kNeither == critical_node->weight)
+ {
+ critical_node->weight = critical_node->dir;
+ }
+ // If direction is different than weight, then it will now be balanced
+ else if (critical_node->dir != critical_node->weight)
+ {
+ critical_node->weight = kNeither;
+ }
+ // Rotate is required to balance the tree at the critical node
+ else
+ {
+ // If critical node matches child node direction then perform a two
+ // node rotate in the direction of the critical node
+ if (critical_node->weight == critical_node->children[critical_node->dir]->dir)
+ {
+ rotate_2node(critical_node, critical_node->dir);
+ }
+ // Otherwise perform a three node rotation in the direction of the
+ // critical node
+ else
+ {
+ rotate_3node(critical_node, critical_node->dir,
+ critical_node->children[critical_node->dir]->children[1 - critical_node->dir]->dir);
+ }
+ }
+ }
+
+ //*************************************************************************
+ /// Find the node whose key would go before all the other keys from the
+ /// position provided
+ //*************************************************************************
+ Node* find_limit_node(Node* position, const int8_t dir) const
+ {
+ // Something at this position and in the direction specified? keep going
+ Node* limit_node = position;
+ while (limit_node && limit_node->children[dir])
+ {
+ limit_node = limit_node->children[dir];
+ }
+
+ // Return the limit node position found
+ return limit_node;
+ }
+
+ //*************************************************************************
+ /// Find the next node in sequence from the node provided
+ //*************************************************************************
+ void next_node(Node*& position) const
+ {
+ if (position)
+ {
+ // Is there a tree on the right? then find the minimum of that tree
+ if (position->children[kRight])
+ {
+ // Return minimum node found
+ position = find_limit_node(position->children[kRight], kLeft);
+ }
+ // Otherwise find the parent of this node
+ else
+ {
+ // Start with current position as parent
+ Node* parent = position;
+ do {
+ // Update current position as previous parent
+ position = parent;
+ // Find parent of current position
+ parent = position->parent; // find_parent_node(root_node, position);
+ // Repeat while previous position was on right side of parent tree
+ } while (parent && parent->children[kRight] == position);
+
+ // Set parent node as the next position
+ position = parent;
+ }
+ }
+ }
+
+ //*************************************************************************
+ /// Find the next node in sequence from the node provided
+ //*************************************************************************
+ void next_node(const Node*& position) const
+ {
+ if (position)
+ {
+ // Is there a tree on the right? then find the minimum of that tree
+ if (position->children[kRight])
+ {
+ // Return minimum node found
+ position = find_limit_node(position->children[kRight], kLeft);
+ }
+ // Otherwise find the parent of this node
+ else
+ {
+ // Start with current position as parent
+ const Node* parent = position;
+ do {
+ // Update current position as previous parent
+ position = parent;
+ // Find parent of current position
+ parent = position->parent;
+ // Repeat while previous position was on right side of parent tree
+ } while (parent && parent->children[kRight] == position);
+
+ // Set parent node as the next position
+ position = parent;
+ }
+ }
+ }
+
+ //*************************************************************************
+ /// Find the previous node in sequence from the node provided
+ //*************************************************************************
+ void prev_node(Node*& position) const
+ {
+ // If starting at the terminal end, the previous node is the maximum node
+ // from the root
+ if (!position)
+ {
+ position = find_limit_node(root_node, kRight);
+ }
+ else
+ {
+ // Is there a tree on the left? then find the maximum of that tree
+ if (position->children[kLeft])
+ {
+ // Return maximum node found
+ position = find_limit_node(position->children[kLeft], kRight);
+ }
+ // Otherwise find the parent of this node
+ else
+ {
+ // Start with current position as parent
+ Node* parent = position;
+ do {
+ // Update current position as previous parent
+ position = parent;
+ // Find parent of current position
+ parent = position->parent;
+ // Repeat while previous position was on left side of parent tree
+ } while (parent && parent->children[kLeft] == position);
+
+ // Set parent node as the next position
+ position = parent;
+ }
+ }
+ }
+
+ //*************************************************************************
+ /// Find the previous node in sequence from the node provided
+ //*************************************************************************
+ void prev_node(const Node*& position) const
+ {
+ // If starting at the terminal end, the previous node is the maximum node
+ // from the root
+ if (!position)
+ {
+ position = find_limit_node(root_node, kRight);
+ }
+ else
+ {
+ // Is there a tree on the left? then find the maximum of that tree
+ if (position->children[kLeft])
+ {
+ // Return maximum node found
+ position = find_limit_node(position->children[kLeft], kRight);
+ }
+ // Otherwise find the parent of this node
+ else
+ {
+ // Start with current position as parent
+ const Node* parent = position;
+ do {
+ // Update current position as previous parent
+ position = parent;
+ // Find parent of current position
+ parent = position->parent;
+ // Repeat while previous position was on left side of parent tree
+ } while (parent && parent->children[kLeft] == position);
+
+ // Set parent node as the next position
+ position = parent;
+ }
+ }
+ }
+
+ //*************************************************************************
+ /// Rotate two nodes at the position provided the to balance the tree
+ //*************************************************************************
+ void rotate_2node(Node*& position, uint8_t dir)
+ {
+ // A C A B
+ // B C -> A E OR B C -> D A
+ // D E B D D E E C
+ // C (new position) becomes the root
+ // A (position) takes ownership of D as its children[kRight] child
+ // C (new position) takes ownership of A as its left child
+ // OR
+ // B (new position) becomes the root
+ // A (position) takes ownership of E as its left child
+ // B (new position) takes ownership of A as its right child
+
+ // Capture new root (either B or C depending on dir) and its parent
+ Node* new_root = position->children[dir];
+
+ // Replace position's previous child with new root's other child
+ position->children[dir] = new_root->children[1 - dir];
+ // Update new root's other child parent pointer
+ if (position->children[dir])
+ {
+ position->children[dir]->parent = position;
+ }
+
+ // New root's parent becomes current position's parent
+ new_root->parent = position->parent;
+ new_root->children[1 - dir] = position;
+ new_root->dir = 1 - dir;
+
+ // Clear weight factor from current position
+ position->weight = kNeither;
+ // Position's parent becomes new_root
+ position->parent = new_root;
+ position = new_root;
+ // Clear weight factor from new root
+ position->weight = kNeither;
+ }
+
+ //*************************************************************************
+ /// Rotate three nodes at the position provided the to balance the tree
+ //*************************************************************************
+ void rotate_3node(Node*& position, uint8_t dir, uint8_t third)
+ {
+ // __A__ __E__ __A__ __D__
+ // _B_ C -> B A OR B _C_ -> A C
+ // D E D F G C D E B F G E
+ // F G F G
+ // E (new position) becomes the root
+ // B (position) takes ownership of F as its left child
+ // A takes ownership of G as its right child
+ // OR
+ // D (new position) becomes the root
+ // A (position) takes ownership of F as its right child
+ // C takes ownership of G as its left child
+
+ // Capture new root (either E or D depending on dir)
+ Node* new_root = position->children[dir]->children[1 - dir];
+ // Set weight factor for B or C based on F or G existing and being a different than dir
+ position->children[dir]->weight = third != kNeither && third != dir ? dir : kNeither;
+
+ // Detach new root from its tree (replace with new roots child)
+ position->children[dir]->children[1 - dir] = new_root->children[dir];
+ // Update new roots child parent pointer
+ if (new_root->children[dir])
+ {
+ new_root->children[dir]->parent = position->children[dir];
+ }
+
+ // Attach current left tree to new root and update its parent
+ new_root->children[dir] = position->children[dir];
+ position->children[dir]->parent = new_root;
+
+ // Set weight factor for A based on F or G
+ position->weight = third != kNeither && third == dir ? 1 - dir : kNeither;
+
+ // Move new root's right tree to current roots left tree
+ position->children[dir] = new_root->children[1 - dir];
+ if (new_root->children[1 - dir])
+ {
+ new_root->children[1 - dir]->parent = position;
+ }
+
+ // Attach current root to new roots right tree and assume its parent
+ new_root->parent = position->parent;
+ new_root->children[1 - dir] = position;
+ new_root->dir = 1 - dir;
+
+ // Update current position's parent and replace with new root
+ position->parent = new_root;
+ position = new_root;
+ // Clear weight factor for new current position
+ position->weight = kNeither;
+ }
+
+ size_type current_size; ///< The number of the used nodes.
+ const size_type MAX_SIZE; ///< The maximum size of the set.
+ Node* root_node; ///< The node that acts as the multiset root.
+ };
+}
+
+#undef ETL_FILE
+
+#endif
diff --git a/lib/etl/private/pool_base.h b/lib/etl/private/pool_base.h
new file mode 100644
index 0000000..7a35816
--- /dev/null
+++ b/lib/etl/private/pool_base.h
@@ -0,0 +1,159 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_IN_IPOOL_H__
+#error This header is a private element of etl::pool & etl::ipool
+#endif
+
+#ifndef __ETL_POOL_BASE__
+#define __ETL_POOL_BASE__
+
+#include <stddef.h>
+
+#include "../exception.h"
+#include "../error_handler.h"
+#include "../error_handler.h"
+
+#undef ETL_FILE
+#define ETL_FILE "11"
+
+namespace etl
+{
+ //***************************************************************************
+ /// The base class for pool exceptions.
+ ///\ingroup pool
+ //***************************************************************************
+ class pool_exception : public exception
+ {
+ public:
+
+ pool_exception(string_type what, string_type file_name, numeric_type line_number)
+ : exception(what, file_name, line_number)
+ {}
+ };
+
+ //***************************************************************************
+ /// The exception thrown when the pool has no more free items.
+ ///\ingroup pool
+ //***************************************************************************
+ class pool_no_allocation : public pool_exception
+ {
+ public:
+
+ explicit pool_no_allocation(string_type file_name, numeric_type line_number)
+ : pool_exception(ETL_ERROR_TEXT("pool:allocation", ETL_FILE"A"), file_name, line_number)
+ {}
+ };
+
+ //***************************************************************************
+ /// The exception thrown when an object is released which does not belong to the pool.
+ ///\ingroup pool
+ //***************************************************************************
+ class pool_object_not_in_pool : public pool_exception
+ {
+ public:
+
+ pool_object_not_in_pool(string_type file_name, numeric_type line_number)
+ : pool_exception(ETL_ERROR_TEXT("pool:notinpool", ETL_FILE"B"), file_name, line_number)
+ {}
+ };
+
+ //*************************************************************************
+ /// The base class for all templated pool types.
+ ///\ingroup pool
+ //*************************************************************************
+ class pool_base
+ {
+ public:
+
+ //*************************************************************************
+ /// Returns the maximum number of items in the pool.
+ //*************************************************************************
+ size_t max_size() const
+ {
+ return MAX_SIZE;
+ }
+
+ //*************************************************************************
+ /// Returns the number of free items in the pool.
+ //*************************************************************************
+ size_t available() const
+ {
+ return MAX_SIZE - items_allocated;
+ }
+
+ //*************************************************************************
+ /// Returns the number of allocated items in the pool.
+ //*************************************************************************
+ size_t size() const
+ {
+ return items_allocated;
+ }
+
+ //*************************************************************************
+ /// Checks to see if there are no allocated items in the pool.
+ /// \return <b>true</b> if there are none allocated.
+ //*************************************************************************
+ bool empty() const
+ {
+ return items_allocated == 0;
+ }
+
+ //*************************************************************************
+ /// Checks to see if there are no free items in the pool.
+ /// \return <b>true</b> if there are none free.
+ //*************************************************************************
+ bool full() const
+ {
+ return items_allocated == MAX_SIZE;
+ }
+
+ protected:
+
+ //*************************************************************************
+ /// Constructor
+ //*************************************************************************
+ pool_base(size_t max_size)
+ : next_free(0),
+ items_allocated(0),
+ MAX_SIZE(max_size)
+ {
+ }
+
+ size_t next_free; ///< The next free slot in the block.
+ size_t items_allocated; ///< The number of items allocated.
+ const size_t MAX_SIZE; ///< The maximum number of objects that can be allocated.
+ };
+}
+
+#undef ETL_FILE
+
+#endif
+
diff --git a/lib/etl/private/pvoidvector.h b/lib/etl/private/pvoidvector.h
new file mode 100644
index 0000000..67fdd4e
--- /dev/null
+++ b/lib/etl/private/pvoidvector.h
@@ -0,0 +1,627 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_PVOIDVECTOR__
+#define __ETL_PVOIDVECTOR__
+
+#define __ETL_IN_PVOIDVECTOR__
+
+#include <iterator>
+#include <algorithm>
+#include <functional>
+#include <stddef.h>
+
+#include "../platform.h"
+#include "../algorithm.h"
+#include "vector_base.h"
+#include "../type_traits.h"
+#include "../error_handler.h"
+
+#ifdef ETL_COMPILER_GCC
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#endif
+
+#ifdef ETL_COMPILER_MICROSOFT
+#undef min
+#endif
+
+namespace etl
+{
+ //***************************************************************************
+ /// The base class for void* vectors.
+ ///\ingroup vector
+ //***************************************************************************
+ class pvoidvector : public vector_base
+ {
+ public:
+
+ typedef void* value_type;
+ typedef void*& reference;
+ typedef const void*& const_reference;
+ typedef void** pointer;
+ typedef const void** const_pointer;
+ typedef void** iterator;
+ typedef const void** const_iterator;
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+ typedef size_t size_type;
+ typedef typename std::iterator_traits<iterator>::difference_type difference_type;
+
+ public:
+
+ //*********************************************************************
+ /// Returns an iterator to the beginning of the vector.
+ ///\return An iterator to the beginning of the vector.
+ //*********************************************************************
+ iterator begin()
+ {
+ return &p_buffer[0];
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the beginning of the vector.
+ ///\return A const iterator to the beginning of the vector.
+ //*********************************************************************
+ const_iterator begin() const
+ {
+ return const_iterator(&p_buffer[0]);
+ }
+
+ //*********************************************************************
+ /// Returns an iterator to the end of the vector.
+ ///\return An iterator to the end of the vector.
+ //*********************************************************************
+ iterator end()
+ {
+ return &p_buffer[current_size];
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the end of the vector.
+ ///\return A const iterator to the end of the vector.
+ //*********************************************************************
+ const_iterator end() const
+ {
+ return const_iterator(&p_buffer[current_size]);
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the beginning of the vector.
+ ///\return A const iterator to the beginning of the vector.
+ //*********************************************************************
+ const_iterator cbegin() const
+ {
+ return const_iterator(&p_buffer[0]);
+ }
+
+ //*********************************************************************
+ /// Returns a const_iterator to the end of the vector.
+ ///\return A const iterator to the end of the vector.
+ //*********************************************************************
+ const_iterator cend() const
+ {
+ return const_iterator(&p_buffer[current_size]);
+ }
+
+ //*********************************************************************
+ /// Returns an reverse iterator to the reverse beginning of the vector.
+ ///\return Iterator to the reverse beginning of the vector.
+ //*********************************************************************
+ reverse_iterator rbegin()
+ {
+ return reverse_iterator(end());
+ }
+
+ //*********************************************************************
+ /// Returns a const reverse iterator to the reverse beginning of the vector.
+ ///\return Const iterator to the reverse beginning of the vector.
+ //*********************************************************************
+ const_reverse_iterator rbegin() const
+ {
+ return const_reverse_iterator(end());
+ }
+
+ //*********************************************************************
+ /// Returns a reverse iterator to the end + 1 of the vector.
+ ///\return Reverse iterator to the end + 1 of the vector.
+ //*********************************************************************
+ reverse_iterator rend()
+ {
+ return reverse_iterator(begin());
+ }
+
+ //*********************************************************************
+ /// Returns a const reverse iterator to the end + 1 of the vector.
+ ///\return Const reverse iterator to the end + 1 of the vector.
+ //*********************************************************************
+ const_reverse_iterator rend() const
+ {
+ return const_reverse_iterator(begin());
+ }
+
+ //*********************************************************************
+ /// Returns a const reverse iterator to the reverse beginning of the vector.
+ ///\return Const reverse iterator to the reverse beginning of the vector.
+ //*********************************************************************
+ const_reverse_iterator crbegin() const
+ {
+ return const_reverse_iterator(cend());
+ }
+
+ //*********************************************************************
+ /// Returns a const reverse iterator to the end + 1 of the vector.
+ ///\return Const reverse iterator to the end + 1 of the vector.
+ //*********************************************************************
+ const_reverse_iterator crend() const
+ {
+ return const_reverse_iterator(cbegin());
+ }
+
+ //*********************************************************************
+ /// Resizes the vector.
+ /// If asserts or exceptions are enabled and the new size is larger than the
+ /// maximum then a vector_full is thrown.
+ ///\param new_size The new size.
+ //*********************************************************************
+ void resize(size_t new_size)
+ {
+ ETL_ASSERT(new_size <= MAX_SIZE, ETL_ERROR(vector_full));
+
+ current_size = new_size;
+ }
+
+ //*********************************************************************
+ /// Resizes the vector.
+ /// If asserts or exceptions are enabled and the new size is larger than the
+ /// maximum then a vector_full is thrown.
+ ///\param new_size The new size.
+ ///\param value The value to fill new elements with. Default = default constructed value.
+ //*********************************************************************
+ void resize(size_t new_size, value_type value)
+ {
+ ETL_ASSERT(new_size <= MAX_SIZE, ETL_ERROR(vector_full));
+
+ // Size up if necessary.
+ while (current_size < new_size)
+ {
+ p_buffer[current_size++] = value;
+ }
+
+ current_size = new_size;
+ }
+
+ //*********************************************************************
+ /// Returns a reference to the value at index 'i'
+ ///\param i The index.
+ ///\return A reference to the value at index 'i'
+ //*********************************************************************
+ reference operator [](size_t i)
+ {
+ return p_buffer[i];
+ }
+
+ //*********************************************************************
+ /// Returns a const reference to the value at index 'i'
+ ///\param i The index.
+ ///\return A const reference to the value at index 'i'
+ //*********************************************************************
+ const_reference operator [](size_t i) const
+ {
+ return const_reference(p_buffer[i]);
+ }
+
+ //*********************************************************************
+ /// Returns a reference to the value at index 'i'
+ /// If asserts or exceptions are enabled, emits an etl::vector_out_of_bounds if the index is out of range.
+ ///\param i The index.
+ ///\return A reference to the value at index 'i'
+ //*********************************************************************
+ reference at(size_t i)
+ {
+ ETL_ASSERT(i < current_size, ETL_ERROR(vector_out_of_bounds));
+ return p_buffer[i];
+ }
+
+ //*********************************************************************
+ /// Returns a const reference to the value at index 'i'
+ /// If asserts or exceptions are enabled, emits an etl::vector_out_of_bounds if the index is out of range.
+ ///\param i The index.
+ ///\return A const reference to the value at index 'i'
+ //*********************************************************************
+ const_reference at(size_t i) const
+ {
+ ETL_ASSERT(i < current_size, ETL_ERROR(vector_out_of_bounds));
+ return const_reference(p_buffer[i]);
+ }
+
+ //*********************************************************************
+ /// Returns a reference to the first element.
+ ///\return A reference to the first element.
+ //*********************************************************************
+ reference front()
+ {
+ return p_buffer[0];
+ }
+
+ //*********************************************************************
+ /// Returns a const reference to the first element.
+ ///\return A const reference to the first element.
+ //*********************************************************************
+ const_reference front() const
+ {
+ return const_reference(p_buffer[0]);
+ }
+
+ //*********************************************************************
+ /// Returns a reference to the last element.
+ ///\return A reference to the last element.
+ //*********************************************************************
+ reference back()
+ {
+ return p_buffer[current_size - 1];
+ }
+
+ //*********************************************************************
+ /// Returns a const reference to the last element.
+ ///\return A const reference to the last element.
+ //*********************************************************************
+ const_reference back() const
+ {
+ return const_reference(p_buffer[current_size - 1]);
+ }
+
+ //*********************************************************************
+ /// Returns a pointer to the beginning of the vector data.
+ ///\return A pointer to the beginning of the vector data.
+ //*********************************************************************
+ pointer data()
+ {
+ return p_buffer;
+ }
+
+ //*********************************************************************
+ /// Returns a const pointer to the beginning of the vector data.
+ ///\return A const pointer to the beginning of the vector data.
+ //*********************************************************************
+ const_pointer data() const
+ {
+ return const_pointer(p_buffer);
+ }
+
+ //*********************************************************************
+ /// Assigns values to the vector.
+ /// If asserts or exceptions are enabled, emits vector_full if the vector does not have enough free space.
+ /// If asserts or exceptions are enabled, emits vector_iterator if the iterators are reversed.
+ ///\param first The iterator to the first element.
+ ///\param last The iterator to the last element + 1.
+ //*********************************************************************
+ template <typename TIterator>
+ void assign(TIterator first, TIterator last)
+ {
+#ifdef _DEBUG
+ difference_type count = std::distance(first, last);
+ ETL_ASSERT(static_cast<size_t>(count) <= MAX_SIZE, ETL_ERROR(vector_full));
+#endif
+
+ initialise();
+
+ while (first != last)
+ {
+ p_buffer[current_size++] = const_cast<void*>(*first++);
+ }
+ }
+
+ //*********************************************************************
+ /// Assigns values to the vector.
+ /// If asserts or exceptions are enabled, emits vector_full if the vector does not have enough free space.
+ ///\param n The number of elements to add.
+ ///\param value The value to insert for each element.
+ //*********************************************************************
+ void assign(size_t n, value_type value)
+ {
+ initialise();
+
+ ETL_ASSERT(n <= MAX_SIZE, ETL_ERROR(vector_full));
+
+ for (size_t current_size = 0; current_size < n; ++current_size)
+ {
+ p_buffer[current_size] = value;
+ }
+ }
+
+ //*************************************************************************
+ /// Clears the vector.
+ //*************************************************************************
+ void clear()
+ {
+ initialise();
+ }
+
+ //*************************************************************************
+ /// Increases the size of the vector by one, but does not initialise the new element.
+ /// If asserts or exceptions are enabled, throws a vector_full if the vector is already full.
+ //*************************************************************************
+ void push_back()
+ {
+#if defined(ETL_CHECK_PUSH_POP)
+ ETL_ASSERT(current_size != MAX_SIZE, ETL_ERROR(vector_full));
+#endif
+
+ ++current_size;
+ }
+
+ //*********************************************************************
+ /// Inserts a value at the end of the vector.
+ /// If asserts or exceptions are enabled, emits vector_full if the vector is already full.
+ ///\param value The value to add.
+ //*********************************************************************
+ void push_back(value_type value)
+ {
+#if defined(ETL_CHECK_PUSH_POP)
+ ETL_ASSERT(current_size != MAX_SIZE, ETL_ERROR(vector_full));
+#endif
+ p_buffer[current_size++] = value;
+ }
+
+ //*************************************************************************
+ /// Removes an element from the end of the vector.
+ /// Does nothing if the vector is empty.
+ //*************************************************************************
+ void pop_back()
+ {
+#if defined(ETL_CHECK_PUSH_POP)
+ ETL_ASSERT(current_size > 0, ETL_ERROR(vector_empty));
+#endif
+ --current_size;
+ }
+
+ //*********************************************************************
+ /// Inserts a value to the vector.
+ /// If asserts or exceptions are enabled, emits vector_full if the vector is already full.
+ ///\param position The position to insert before.
+ ///\param value The value to insert.
+ //*********************************************************************
+ iterator insert(iterator position, value_type value)
+ {
+ ETL_ASSERT((current_size)+1 <= MAX_SIZE, ETL_ERROR(vector_full));
+
+ if (position != end())
+ {
+ ++current_size;
+ std::copy_backward(position, end() - 1, end());
+ *position = value;
+ }
+ else
+ {
+ p_buffer[current_size++] = value;
+ }
+
+ return position;
+ }
+
+ //*********************************************************************
+ /// Inserts 'n' values to the vector.
+ /// If asserts or exceptions are enabled, emits vector_full if the vector does not have enough free space.
+ ///\param position The position to insert before.
+ ///\param n The number of elements to add.
+ ///\param value The value to insert.
+ //*********************************************************************
+ void insert(iterator position, size_t n, value_type value)
+ {
+ ETL_ASSERT((current_size)+1 <= MAX_SIZE, ETL_ERROR(vector_full));
+
+ if (position == end())
+ {
+ while (n > 0)
+ {
+ p_buffer[current_size++] = value;
+ --n;
+ }
+ }
+ else
+ {
+ // Create copy (backwards).
+ size_t n_insert = n;
+ size_t from = size() - 1;
+ size_t to = from + n_insert;
+ size_t n_move = std::distance(position, end());
+ size_t n_create_copy = std::min(n_insert, n_move);
+
+ for (size_t i = 0; i < n_create_copy; ++i)
+ {
+ p_buffer[to--] = p_buffer[from--];
+ }
+
+ // Copy old.
+ size_t insert_index = std::distance(begin(), position);
+ from = insert_index;
+ to = from + n_insert;
+ size_t n_copy_old = (size() > n_insert) ? size() - n_insert : 0;
+ etl::copy_n(&p_buffer[from], n_copy_old, &p_buffer[to]);
+
+ // Copy new.
+ to = insert_index;
+
+ size_t n_create_new = (n_insert > n_create_copy) ? n_insert - n_create_copy : 0;
+ size_t n_copy_new = (n_insert > n_create_new) ? n_insert - n_create_new : 0;
+ std::fill_n(&p_buffer[to], n_copy_new, value);
+
+ // Create new.
+ to = size();
+ for (size_t i = 0; i < n_create_new; ++i)
+ {
+ p_buffer[to++] = value;
+ }
+
+ current_size += n_insert;
+ }
+ }
+
+ //*********************************************************************
+ /// Inserts a range of values to the vector.
+ /// If asserts or exceptions are enabled, emits vector_full if the vector does not have enough free space.
+ /// For fundamental and pointer types.
+ ///\param position The position to insert before.
+ ///\param first The first element to add.
+ ///\param last The last + 1 element to add.
+ //*********************************************************************
+ template <typename TIterator>
+ void insert(iterator position, TIterator first, TIterator last)
+ {
+ size_t count = std::distance(first, last);
+
+ ETL_ASSERT((current_size)+count <= MAX_SIZE, ETL_ERROR(vector_full));
+
+ if (position == end())
+ {
+ while (first != last)
+ {
+ p_buffer[current_size++] = *first++;
+ }
+ }
+ else
+ {
+ size_t insert_index = std::distance(begin(), position);
+ size_t n_insert = count;
+
+ // Create copy (backwards).
+ size_t from = size() - 1;
+ size_t to = from + n_insert;
+ size_t n_move = std::distance(position, end());
+ size_t n_create_copy = std::min(n_insert, n_move);
+ for (size_t i = 0; i < n_create_copy; ++i)
+ {
+ p_buffer[to--] = p_buffer[from--];
+ }
+
+ // Copy old.
+ from = insert_index;
+ to = from + n_insert;
+ size_t n_copy_old = (size() > n_insert) ? size() - n_insert : 0;
+ etl::copy_n(&p_buffer[from], n_copy_old, &p_buffer[to]);
+
+ // Copy new.
+ to = insert_index;
+ size_t n_create_new = (n_insert > n_create_copy) ? n_insert - n_create_copy : 0;
+ size_t n_copy_new = (n_insert > n_create_new) ? n_insert - n_create_new : 0;
+ etl::copy_n(first, n_copy_new, &p_buffer[to]);
+ first += n_copy_new;
+
+ // Create new.
+ to = size();
+ for (size_t i = 0; i < n_create_new; ++i)
+ {
+ p_buffer[to++] = *first++;
+ }
+
+ current_size += n_insert;
+ }
+ }
+
+ //*********************************************************************
+ /// Erases an element.
+ ///\param i_element Iterator to the element.
+ ///\return An iterator pointing to the element that followed the erased element.
+ //*********************************************************************
+ iterator erase(iterator i_element)
+ {
+ std::copy(i_element + 1, end(), i_element);
+ --current_size;
+
+ return i_element;
+ }
+
+ //*********************************************************************
+ /// Erases a range of elements.
+ /// The range includes all the elements between first and last, including the
+ /// element pointed by first, but not the one pointed by last.
+ ///\param first Iterator to the first element.
+ ///\param last Iterator to the last element.
+ ///\return An iterator pointing to the element that followed the erased element.
+ //*********************************************************************
+ iterator erase(iterator first, iterator last)
+ {
+ std::copy(last, end(), first);
+ size_t n_delete = std::distance(first, last);
+
+ // Just adjust the count.
+ current_size -= n_delete;
+
+ return first;
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ pvoidvector& operator = (const pvoidvector& rhs)
+ {
+ if (&rhs != this)
+ {
+ assign(rhs.cbegin(), rhs.cend());
+ }
+
+ return *this;
+ }
+
+ protected:
+
+ //*********************************************************************
+ /// Constructor.
+ //*********************************************************************
+ pvoidvector(void** p_buffer, size_t MAX_SIZE)
+ : vector_base(MAX_SIZE),
+ p_buffer(p_buffer)
+ {
+ }
+
+ //*********************************************************************
+ /// Initialise the vector.
+ //*********************************************************************
+ void initialise()
+ {
+ current_size = 0;
+ }
+
+ void** p_buffer;
+
+ private:
+
+ // Disable copy construction.
+ pvoidvector(const pvoidvector&);
+ };
+}
+
+#ifdef ETL_COMPILER_MICROSOFT
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#undef __ETL_IN_PVOIDVECTOR__
+
+#endif
diff --git a/lib/etl/private/queue_base.h b/lib/etl/private/queue_base.h
new file mode 100644
index 0000000..c7a0aad
--- /dev/null
+++ b/lib/etl/private/queue_base.h
@@ -0,0 +1,165 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_IN_IQUEUE_H__
+#error This header is a private element of etl::queue & etl::iqueue
+#endif
+
+#ifndef __ETL_QUEUE_BASE__
+#define __ETL_QUEUE_BASE__
+
+#include <stddef.h>
+
+#include "../exception.h"
+#include "../error_handler.h"
+
+#undef ETL_FILE
+#define ETL_FILE "13"
+
+namespace etl
+{
+ //***************************************************************************
+ /// The base class for queue exceptions.
+ ///\ingroup queue
+ //***************************************************************************
+ class queue_exception : public exception
+ {
+ public:
+
+ queue_exception(string_type what, string_type file_name, numeric_type line_number)
+ : exception(what, file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// The exception thrown when the queue is full.
+ ///\ingroup queue
+ //***************************************************************************
+ class queue_full : public queue_exception
+ {
+ public:
+
+ queue_full(string_type file_name, numeric_type line_number)
+ : queue_exception(ETL_ERROR_TEXT("queue:full", ETL_FILE"A"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// The exception thrown when the queue is empty.
+ ///\ingroup queue
+ //***************************************************************************
+ class queue_empty : public queue_exception
+ {
+ public:
+
+ queue_empty(string_type file_name, numeric_type line_number)
+ : queue_exception(ETL_ERROR_TEXT("queue:empty", ETL_FILE"B"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// The base class for all queues.
+ ///\ingroup queue
+ //***************************************************************************
+ class queue_base
+ {
+ public:
+
+ typedef size_t size_type; ///< The type used for determining the size of queue.
+
+ //*************************************************************************
+ /// Returns the current number of items in the queue.
+ //*************************************************************************
+ size_type size() const
+ {
+ return current_size;
+ }
+
+ //*************************************************************************
+ /// Returns the maximum number of items that can be queued.
+ //*************************************************************************
+ size_type max_size() const
+ {
+ return MAX_SIZE;
+ }
+
+ //*************************************************************************
+ /// Checks to see if the queue is empty.
+ /// \return <b>true</b> if the queue is empty, otherwise <b>false</b>
+ //*************************************************************************
+ bool empty() const
+ {
+ return current_size == 0;
+ }
+
+ //*************************************************************************
+ /// Checks to see if the queue is full.
+ /// \return <b>true</b> if the queue is full, otherwise <b>false</b>
+ //*************************************************************************
+ bool full() const
+ {
+ return current_size == MAX_SIZE;
+ }
+
+ //*************************************************************************
+ /// Returns the remaining capacity.
+ ///\return The remaining capacity.
+ //*************************************************************************
+ size_t available() const
+ {
+ return max_size() - size();
+ }
+
+ protected:
+
+ //*************************************************************************
+ /// The constructor that is called from derived classes.
+ //*************************************************************************
+ queue_base(size_type max_size)
+ : in(0),
+ out(0),
+ current_size(0),
+ MAX_SIZE(max_size)
+ {
+ }
+
+ size_type in; ///< Where to input new data.
+ size_type out; ///< Where to get the oldest data.
+ size_type current_size; ///< The number of items in the queue.
+ const size_type MAX_SIZE; ///< The maximum number of items in the queue.
+ };
+}
+
+#undef ETL_FILE
+
+#endif
diff --git a/lib/etl/private/set_base.h b/lib/etl/private/set_base.h
new file mode 100644
index 0000000..32a72c2
--- /dev/null
+++ b/lib/etl/private/set_base.h
@@ -0,0 +1,427 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2015 jwellbelove, rlindeman
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#if !defined(__ETL_IN_ISET_H__)
+#error This header is a private element of etl::set & etl::iset
+#endif
+
+#ifndef __ETL_SET_BASE__
+#define __ETL_SET_BASE__
+
+#include <stddef.h>
+#include "../exception.h"
+#include "../error_handler.h"
+
+#define ETL_FILE "14"
+
+namespace etl
+{
+ //***************************************************************************
+ /// Exception for the set.
+ ///\ingroup set
+ //***************************************************************************
+ class set_exception : public exception
+ {
+ public:
+
+ set_exception(string_type what, string_type file_name, numeric_type line_number)
+ : exception(what, file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// Full exception for the set.
+ ///\ingroup set
+ //***************************************************************************
+ class set_full : public set_exception
+ {
+ public:
+
+ set_full(string_type file_name, numeric_type line_number)
+ : set_exception(ETL_ERROR_TEXT("set:full", ETL_FILE"A"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// Map out of bounds exception.
+ ///\ingroup set
+ //***************************************************************************
+ class set_out_of_bounds : public set_exception
+ {
+ public:
+
+ set_out_of_bounds(string_type file_name, numeric_type line_number)
+ : set_exception(ETL_ERROR_TEXT("set:bounds", ETL_FILE"B"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// Iterator exception for the set.
+ ///\ingroup set
+ //***************************************************************************
+ class set_iterator : public set_exception
+ {
+ public:
+
+ set_iterator(string_type file_name, numeric_type line_number)
+ : set_exception(ETL_ERROR_TEXT("set:iterator problem", ETL_FILE"C"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// The base class for all sets.
+ ///\ingroup set
+ //***************************************************************************
+ class set_base
+ {
+ public:
+
+ typedef size_t size_type; ///< The type used for determining the size of set.
+
+ //*************************************************************************
+ /// Gets the size of the set.
+ //*************************************************************************
+ size_type size() const
+ {
+ return current_size;
+ }
+
+ //*************************************************************************
+ /// Gets the maximum possible size of the set.
+ //*************************************************************************
+ size_type max_size() const
+ {
+ return MAX_SIZE;
+ }
+
+ //*************************************************************************
+ /// Checks to see if the set is empty.
+ //*************************************************************************
+ bool empty() const
+ {
+ return current_size == 0;
+ }
+
+ //*************************************************************************
+ /// Checks to see if the set is full.
+ //*************************************************************************
+ bool full() const
+ {
+ return current_size == MAX_SIZE;
+ }
+
+ //*************************************************************************
+ /// Returns the capacity of the vector.
+ ///\return The capacity of the vector.
+ //*************************************************************************
+ size_type capacity() const
+ {
+ return MAX_SIZE;
+ }
+
+ //*************************************************************************
+ /// Returns the remaining capacity.
+ ///\return The remaining capacity.
+ //*************************************************************************
+ size_t available() const
+ {
+ return max_size() - size();
+ }
+
+ protected:
+
+ enum
+ {
+ kLeft = 0,
+ kRight = 1,
+ kNeither = 2
+ };
+
+ //*************************************************************************
+ /// The node element in the set.
+ //*************************************************************************
+ struct Node
+ {
+ //***********************************************************************
+ /// Constructor
+ //***********************************************************************
+ Node() :
+ weight(kNeither),
+ dir(kNeither)
+ {
+ }
+
+ //***********************************************************************
+ /// Marks the node as a leaf.
+ //***********************************************************************
+ void mark_as_leaf()
+ {
+ weight = kNeither;
+ dir = kNeither;
+ children[0] = nullptr;
+ children[1] = nullptr;
+ }
+
+ Node* children[2];
+ uint8_t weight;
+ uint8_t dir;
+ };
+
+ //*************************************************************************
+ /// The constructor that is called from derived classes.
+ //*************************************************************************
+ set_base(size_type max_size)
+ : current_size(0)
+ , MAX_SIZE(max_size)
+ , root_node(nullptr)
+
+ {
+ }
+
+ //*************************************************************************
+ /// Attach the provided node to the position provided
+ //*************************************************************************
+ void attach_node(Node*& position, Node& node)
+ {
+ // Mark new node as leaf on attach to tree at position provided
+ node.mark_as_leaf();
+
+ // Add the node here
+ position = &node;
+
+ // One more.
+ ++current_size;
+ }
+
+ //*************************************************************************
+ /// Detach the node at the position provided
+ //*************************************************************************
+ void detach_node(Node*& position, Node*& replacement)
+ {
+ // Make temporary copy of actual nodes involved because we might lose
+ // their references in the process (e.g. position is the same as
+ // replacement or replacement is a child of position)
+ Node* detached = position;
+ Node* swap = replacement;
+
+ // Update current position to point to swap (replacement) node first
+ position = swap;
+
+ // Update replacement node to point to child in opposite direction
+ // otherwise we might lose the other child of the swap node
+ replacement = swap->children[1 - swap->dir];
+
+ // Point swap node to detached node's children and weight
+ swap->children[kLeft] = detached->children[kLeft];
+ swap->children[kRight] = detached->children[kRight];
+ swap->weight = detached->weight;
+ }
+
+ //*************************************************************************
+ /// Balance the critical node at the position provided as needed
+ //*************************************************************************
+ void balance_node(Node*& critical_node)
+ {
+ // Step 1: Update weights for all children of the critical node up to the
+ // newly inserted node. This step is costly (in terms of traversing nodes
+ // multiple times during insertion) but doesn't require as much recursion
+ Node* weight_node = critical_node->children[critical_node->dir];
+ while (weight_node)
+ {
+ // Keep going until we reach a terminal node (dir == kNeither)
+ if (kNeither != weight_node->dir)
+ {
+ // Does this insert balance the previous weight factor value?
+ if (weight_node->weight == 1 - weight_node->dir)
+ {
+ weight_node->weight = kNeither;
+ }
+ else
+ {
+ weight_node->weight = weight_node->dir;
+ }
+
+ // Update weight factor node to point to next node
+ weight_node = weight_node->children[weight_node->dir];
+ }
+ else
+ {
+ // Stop loop, terminal node found
+ break;
+ }
+ } // while(weight_node)
+
+ // Step 2: Update weight for critical_node or rotate tree to balance node
+ if (kNeither == critical_node->weight)
+ {
+ critical_node->weight = critical_node->dir;
+ }
+ // If direction is different than weight, then it will now be balanced
+ else if (critical_node->dir != critical_node->weight)
+ {
+ critical_node->weight = kNeither;
+ }
+ // Rotate is required to balance the tree at the critical node
+ else
+ {
+ // If critical node matches child node direction then perform a two
+ // node rotate in the direction of the critical node
+ if (critical_node->weight == critical_node->children[critical_node->dir]->dir)
+ {
+ rotate_2node(critical_node, critical_node->dir);
+ }
+ // Otherwise perform a three node rotation in the direction of the
+ // critical node
+ else
+ {
+ rotate_3node(critical_node, critical_node->dir,
+ critical_node->children[critical_node->dir]->children[1 - critical_node->dir]->dir);
+ }
+ }
+ }
+
+ //*************************************************************************
+ /// Find the node whose key would go before all the other keys from the
+ /// position provided
+ //*************************************************************************
+ Node* find_limit_node(Node* position, const int8_t dir) const
+ {
+ // Something at this position and in the direction specified? keep going
+ Node* limit_node = position;
+ while (limit_node && limit_node->children[dir])
+ {
+ limit_node = limit_node->children[dir];
+ }
+
+ // Return the limit node position found
+ return limit_node;
+ }
+
+ //*************************************************************************
+ /// Find the node whose key would go before all the other keys from the
+ /// position provided
+ //*************************************************************************
+ const Node* find_limit_node(const Node* position, const int8_t dir) const
+ {
+ // Something at this position and in the direction specified? keep going
+ const Node* limit_node = position;
+ while (limit_node && limit_node->children[dir])
+ {
+ limit_node = limit_node->children[dir];
+ }
+
+ // Return the limit node position found
+ return limit_node;
+ }
+
+ //*************************************************************************
+ /// Rotate two nodes at the position provided the to balance the tree
+ //*************************************************************************
+ void rotate_2node(Node*& position, uint8_t dir)
+ {
+ // A C A B
+ // B C -> A E OR B C -> D A
+ // D E B D D E E C
+ // C (new position) becomes the root
+ // A (position) takes ownership of D as its children[kRight] child
+ // C (new position) takes ownership of A as its left child
+ // OR
+ // B (new position) becomes the root
+ // A (position) takes ownership of E as its left child
+ // B (new position) takes ownership of A as its right child
+
+ // Capture new root
+ Node* new_root = position->children[dir];
+ // Replace position's previous child with new root's other child
+ position->children[dir] = new_root->children[1 - dir];
+ // New root now becomes parent of current position
+ new_root->children[1 - dir] = position;
+ // Clear weight factor from current position
+ position->weight = kNeither;
+ // Newly detached right now becomes current position
+ position = new_root;
+ // Clear weight factor from new root
+ position->weight = kNeither;
+ }
+
+ //*************************************************************************
+ /// Rotate three nodes at the position provided the to balance the tree
+ //*************************************************************************
+ void rotate_3node(Node*& position, uint8_t dir, uint8_t third)
+ {
+ // __A__ __E__ __A__ __D__
+ // _B_ C -> B A OR B _C_ -> A C
+ // D E D F G C D E B F G E
+ // F G F G
+ // E (new position) becomes the root
+ // B (position) takes ownership of F as its left child
+ // A takes ownership of G as its right child
+ // OR
+ // D (new position) becomes the root
+ // A (position) takes ownership of F as its right child
+ // C takes ownership of G as its left child
+
+ // Capture new root (either E or D depending on dir)
+ Node* new_root = position->children[dir]->children[1 - dir];
+ // Set weight factor for B or C based on F or G existing and being a different than dir
+ position->children[dir]->weight = third != kNeither && third != dir ? dir : kNeither;
+
+ // Detach new root from its tree (replace with new roots child)
+ position->children[dir]->children[1 - dir] =
+ new_root->children[dir];
+ // Attach current left tree to new root
+ new_root->children[dir] = position->children[dir];
+ // Set weight factor for A based on F or G
+ position->weight = third != kNeither && third == dir ? 1 - dir : kNeither;
+
+ // Move new root's right tree to current roots left tree
+ position->children[dir] = new_root->children[1 - dir];
+ // Attach current root to new roots right tree
+ new_root->children[1 - dir] = position;
+ // Replace current position with new root
+ position = new_root;
+ // Clear weight factor for new current position
+ position->weight = kNeither;
+ }
+
+
+ size_type current_size; ///< The number of the used nodes.
+ const size_type MAX_SIZE; ///< The maximum size of the set.
+ Node* root_node; ///< The node that acts as the set root.
+ };
+}
+
+#undef ETL_FILE
+
+#endif
diff --git a/lib/etl/private/stack_base.h b/lib/etl/private/stack_base.h
new file mode 100644
index 0000000..e3e6c55
--- /dev/null
+++ b/lib/etl/private/stack_base.h
@@ -0,0 +1,163 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtatoptopg a copy
+of this software and associated documentation files(the "Software"), to deal
+top the Software withtop restriction, topcludtopg withtop limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the followtopg conditions :
+
+The above copyright notice and this permission notice shall be included top all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_IN_ISTACK_H__
+#error This header is a private element of etl::stack & etl::istack
+#endif
+
+#ifndef __ETL_STACK_BASE__
+#define __ETL_STACK_BASE__
+
+#include <stddef.h>
+
+#include "../exception.h"
+#include "../error_handler.h"
+
+#define ETL_FILE "15"
+
+namespace etl
+{
+ //***************************************************************************
+ ///\ingroup stack
+ /// The base class for stack exceptions.
+ //***************************************************************************
+ class stack_exception : public exception
+ {
+ public:
+
+ stack_exception(string_type what, string_type file_name, numeric_type line_number)
+ : exception(what, file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ ///\ingroup stack
+ /// The exception thrown when the stack is full.
+ //***************************************************************************
+ class stack_full : public stack_exception
+ {
+ public:
+
+ stack_full(string_type file_name, numeric_type line_number)
+ : stack_exception(ETL_ERROR_TEXT("stack:full", ETL_FILE"A"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ ///\ingroup stack
+ /// The exception thrown when the stack is empty.
+ //***************************************************************************
+ class stack_empty : public stack_exception
+ {
+ public:
+
+ stack_empty(string_type file_name, numeric_type line_number)
+ : stack_exception(ETL_ERROR_TEXT("stack:empty", ETL_FILE"B"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ ///\ingroup stack
+ /// A fixed capacity stack written in the STL style.
+ /// \warntopg This stack cannot be used for concurrent access from multiple threads.
+ //***************************************************************************
+ class stack_base
+ {
+ public:
+
+ typedef size_t size_type; ///< The type used for determining the size of stack.
+
+ //*************************************************************************
+ /// Checks to see if the stack is empty.
+ /// \return <b>true</b> if the stack is empty, otherwise <b>false</b>
+ //*************************************************************************
+ bool empty() const
+ {
+ return current_size == 0;
+ }
+
+ //*************************************************************************
+ /// Checks to see if the stack is full.
+ /// \return <b>true</b> if the stack is full, otherwise <b>false</b>
+ //*************************************************************************
+ bool full() const
+ {
+ return current_size == MAX_SIZE;
+ }
+
+ //*************************************************************************
+ /// Returns the current number of items top the stack.
+ //*************************************************************************
+ size_type size() const
+ {
+ return current_size;
+ }
+
+ //*************************************************************************
+ /// Returns the maximum number of items that can be stacked.
+ //*************************************************************************
+ size_type max_size() const
+ {
+ return MAX_SIZE;
+ }
+
+ //*************************************************************************
+ /// Returns the remaining capacity.
+ ///\return The remaining capacity.
+ //*************************************************************************
+ size_t available() const
+ {
+ return max_size() - size();
+ }
+
+ protected:
+
+ //*************************************************************************
+ /// The constructor that is called from derived classes.
+ //*************************************************************************
+ stack_base(size_type max_size)
+ : top_index(0),
+ current_size(0),
+ MAX_SIZE(max_size)
+ {
+ }
+
+ size_type top_index; ///< The index of the top of the stack.
+ size_type current_size; ///< The number of items in the stack.
+ const size_type MAX_SIZE; ///< The maximum number of items in the stack.
+ };
+}
+
+#undef ETL_FILE
+
+#endif
diff --git a/lib/etl/private/string_base.h b/lib/etl/private/string_base.h
new file mode 100644
index 0000000..f3e8421
--- /dev/null
+++ b/lib/etl/private/string_base.h
@@ -0,0 +1,217 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_IN_ISTRING_H__
+#error This header is a private element of etl::string & etl::istring
+#endif
+
+#ifndef __ETL_STRING_BASE__
+#define __ETL_STRING_BASE__
+
+#include <stddef.h>
+
+#include "../platform.h"
+#include "../integral_limits.h"
+#include "../exception.h"
+#include "../error_handler.h"
+
+#define ETL_FILE "24"
+
+#ifdef ETL_COMPILER_MICROSOFT
+#undef max
+#endif
+
+namespace etl
+{
+ //***************************************************************************
+ ///\ingroup string
+ /// Exception base for strings
+ //***************************************************************************
+ class string_exception : public exception
+ {
+ public:
+
+ string_exception(string_type what, string_type file_name, numeric_type line_number)
+ : exception(what, file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ ///\ingroup string
+ /// String empty exception.
+ //***************************************************************************
+ class string_empty : public string_exception
+ {
+ public:
+
+ string_empty(string_type file_name, numeric_type line_number)
+ : string_exception(ETL_ERROR_TEXT("string:empty", ETL_FILE"A"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ ///\ingroup string
+ /// String out of bounds exception.
+ //***************************************************************************
+ class string_out_of_bounds : public string_exception
+ {
+ public:
+
+ string_out_of_bounds(string_type file_name, numeric_type line_number)
+ : string_exception(ETL_ERROR_TEXT("string:bounds", ETL_FILE"B"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ ///\ingroup string
+ /// String iterator exception.
+ //***************************************************************************
+ class string_iterator : public string_exception
+ {
+ public:
+
+ string_iterator(string_type file_name, numeric_type line_number)
+ : string_exception(ETL_ERROR_TEXT("string:iterator", ETL_FILE"D"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ ///\ingroup string
+ /// The base class for all templated string types.
+ //***************************************************************************
+ class string_base
+ {
+ public:
+
+ typedef size_t size_type;
+
+ static const size_t npos = etl::integral_limits<size_t>::max;
+
+ //*************************************************************************
+ /// Gets the current size of the string.
+ ///\return The current size of the string.
+ //*************************************************************************
+ size_type size() const
+ {
+ return current_size;
+ }
+
+ //*************************************************************************
+ /// Gets the current size of the string.
+ ///\return The current size of the string.
+ //*************************************************************************
+ size_type length() const
+ {
+ return current_size;
+ }
+
+ //*************************************************************************
+ /// Checks the 'empty' state of the string.
+ ///\return <b>true</b> if empty.
+ //*************************************************************************
+ bool empty() const
+ {
+ return (current_size == 0);
+ }
+
+ //*************************************************************************
+ /// Checks the 'full' state of the string.
+ ///\return <b>true</b> if full.
+ //*************************************************************************
+ bool full() const
+ {
+ return current_size == MAX_SIZE;
+ }
+
+ //*************************************************************************
+ /// Returns the capacity of the string.
+ ///\return The capacity of the string.
+ //*************************************************************************
+ size_type capacity() const
+ {
+ return MAX_SIZE;
+ }
+
+ //*************************************************************************
+ /// Returns the maximum possible size of the string.
+ ///\return The maximum size of the string.
+ //*************************************************************************
+ size_type max_size() const
+ {
+ return MAX_SIZE;
+ }
+
+ //*************************************************************************
+ /// Returns the remaining capacity.
+ ///\return The remaining capacity.
+ //*************************************************************************
+ size_t available() const
+ {
+ return max_size() - size();
+ }
+
+ //*************************************************************************
+ /// Returns whether the string was truncated by the lat operation.
+ ///\return Whether the string was truncated by the lat operation.
+ //*************************************************************************
+ size_t truncated() const
+ {
+ return is_truncated;
+ }
+
+ protected:
+
+ //*************************************************************************
+ /// Constructor.
+ //*************************************************************************
+ string_base(size_t max_size)
+ : is_truncated(false),
+ current_size(0),
+ MAX_SIZE(max_size)
+ {
+ }
+
+ bool is_truncated; ///< Set to true if the operation truncated the string.
+ size_type current_size; ///< The current number of elements in the string.
+ const size_type MAX_SIZE; ///< The maximum number of elements in the string.
+ };
+}
+
+#ifdef ETL_COMPILER_MICROSOFT
+#define max(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+
+#undef ETL_FILE
+
+#endif
diff --git a/lib/etl/private/vector_base.h b/lib/etl/private/vector_base.h
new file mode 100644
index 0000000..4c78b41
--- /dev/null
+++ b/lib/etl/private/vector_base.h
@@ -0,0 +1,185 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#if !defined(__ETL_IN_IVECTOR_H__) && !defined(__ETL_IN_PVOIDVECTOR__)
+#error This header is a private element of etl::vector, etl::ivector & etl::pvoidvector
+#endif
+
+#ifndef __ETL_VECTOR_BASE__
+#define __ETL_VECTOR_BASE__
+
+#include <stddef.h>
+
+#include "../exception.h"
+#include "../error_handler.h"
+
+#define ETL_FILE "17"
+
+namespace etl
+{
+ //***************************************************************************
+ ///\ingroup vector
+ /// Exception base for vectors
+ //***************************************************************************
+ class vector_exception : public exception
+ {
+ public:
+
+ vector_exception(string_type what, string_type file_name, numeric_type line_number)
+ : exception(what, file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ ///\ingroup vector
+ /// Vector full exception.
+ //***************************************************************************
+ class vector_full : public vector_exception
+ {
+ public:
+
+ vector_full(string_type file_name, numeric_type line_number)
+ : vector_exception(ETL_ERROR_TEXT("vector:full", ETL_FILE"A"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ ///\ingroup vector
+ /// Vector empty exception.
+ //***************************************************************************
+ class vector_empty : public vector_exception
+ {
+ public:
+
+ vector_empty(string_type file_name, numeric_type line_number)
+ : vector_exception(ETL_ERROR_TEXT("vector:empty", ETL_FILE"B"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ ///\ingroup vector
+ /// Vector out of bounds exception.
+ //***************************************************************************
+ class vector_out_of_bounds : public vector_exception
+ {
+ public:
+
+ vector_out_of_bounds(string_type file_name, numeric_type line_number)
+ : vector_exception(ETL_ERROR_TEXT("vector:bounds", ETL_FILE"C"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ ///\ingroup vector
+ /// The base class for all templated vector types.
+ //***************************************************************************
+ class vector_base
+ {
+ public:
+
+ typedef size_t size_type;
+
+ //*************************************************************************
+ /// Gets the current size of the vector.
+ ///\return The current size of the vector.
+ //*************************************************************************
+ size_type size() const
+ {
+ return current_size;
+ }
+
+ //*************************************************************************
+ /// Checks the 'empty' state of the vector.
+ ///\return <b>true</b> if empty.
+ //*************************************************************************
+ bool empty() const
+ {
+ return (current_size == 0);
+ }
+
+ //*************************************************************************
+ /// Checks the 'full' state of the vector.
+ ///\return <b>true</b> if full.
+ //*************************************************************************
+ bool full() const
+ {
+ return current_size == MAX_SIZE;
+ }
+
+ //*************************************************************************
+ /// Returns the capacity of the vector.
+ ///\return The capacity of the vector.
+ //*************************************************************************
+ size_type capacity() const
+ {
+ return MAX_SIZE;
+ }
+
+ //*************************************************************************
+ /// Returns the maximum possible size of the vector.
+ ///\return The maximum size of the vector.
+ //*************************************************************************
+ size_type max_size() const
+ {
+ return MAX_SIZE;
+ }
+
+ //*************************************************************************
+ /// Returns the remaining capacity.
+ ///\return The remaining capacity.
+ //*************************************************************************
+ size_t available() const
+ {
+ return max_size() - size();
+ }
+
+ protected:
+
+ //*************************************************************************
+ /// Constructor.
+ //*************************************************************************
+ vector_base(size_t max_size)
+ : current_size(0),
+ MAX_SIZE(max_size)
+ {
+ }
+
+ size_type current_size; ///<The current number of elements in the vector.
+ const size_type MAX_SIZE; ///<The maximum number of elements in the vector.
+ };
+}
+
+#undef ETL_FILE
+
+#endif
diff --git a/lib/etl/queue.h b/lib/etl/queue.h
new file mode 100644
index 0000000..17cdc33
--- /dev/null
+++ b/lib/etl/queue.h
@@ -0,0 +1,108 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_QUEUE__
+#define __ETL_QUEUE__
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "iqueue.h"
+#include "container.h"
+#include "alignment.h"
+#include "array.h"
+
+//*****************************************************************************
+///\defgroup queue queue
+/// A First-in / first-out queue with the capacity defined at compile time,
+/// written in the STL style.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+ //***************************************************************************
+ ///\ingroup queue
+ /// A fixed capacity queue.
+ /// This queue does not support concurrent access by different threads.
+ /// \tparam T The type this queue should support.
+ /// \tparam SIZE The maximum capacity of the queue.
+ //***************************************************************************
+ template <typename T, const size_t SIZE>
+ class queue : public iqueue<T>
+ {
+ public:
+
+ //*************************************************************************
+ /// Default constructor.
+ //*************************************************************************
+ queue()
+ : iqueue<T>(reinterpret_cast<T*>(&buffer[0]), SIZE)
+ {
+ }
+
+ //*************************************************************************
+ /// Copy constructor
+ //*************************************************************************
+ queue(const queue& rhs)
+ : iqueue<T>(reinterpret_cast<T*>(&buffer[0]), SIZE)
+ {
+ iqueue<T>::clone(rhs);
+ }
+
+ //*************************************************************************
+ /// Destructor.
+ //*************************************************************************
+ ~queue()
+ {
+ iqueue<T>::clear();
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ queue& operator = (const queue& rhs)
+ {
+ if (&rhs != this)
+ {
+ iqueue<T>::clone(rhs);
+ }
+
+ return *this;
+ }
+
+ private:
+
+ /// The uninitialised buffer of T used in the stack.
+ typename etl::aligned_storage<sizeof(T), etl::alignment_of<T>::value>::type buffer[SIZE];
+ };
+}
+
+#endif
diff --git a/lib/etl/radix.h b/lib/etl/radix.h
new file mode 100644
index 0000000..61b5636
--- /dev/null
+++ b/lib/etl/radix.h
@@ -0,0 +1,66 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_RADIX__
+#define __ETL_RADIX__
+
+#include <stdint.h>
+
+#include "enum_type.h"
+
+///\defgroup radix radix
+/// Radix constants for binary, octal, decimal and hex.
+///\ingroup etl
+
+namespace etl
+{
+ /// \ingroup radix
+ struct radix
+ {
+ enum enum_type
+ {
+ undefined = 0,
+ binary = 2,
+ octal = 8,
+ decimal = 10,
+ hex = 16
+ };
+
+ DECLARE_ENUM_TYPE(radix, uint8_t)
+ ENUM_TYPE(undefined, "undefined")
+ ENUM_TYPE(binary, "binary")
+ ENUM_TYPE(octal, "octal")
+ ENUM_TYPE(decimal, "decimal")
+ ENUM_TYPE(hex, "hex")
+ END_ENUM_TYPE
+ };
+}
+
+#endif
diff --git a/lib/etl/set.h b/lib/etl/set.h
new file mode 100644
index 0000000..3fb2ec2
--- /dev/null
+++ b/lib/etl/set.h
@@ -0,0 +1,113 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove, rlindeman
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_SET__
+#define __ETL_SET__
+
+#include <stddef.h>
+#include <iterator>
+#include <functional>
+
+#include "iset.h"
+#include "container.h"
+#include "pool.h"
+
+//*****************************************************************************
+///\defgroup set set
+/// A set with the capacity defined at compile time.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+ //*************************************************************************
+ /// A templated set implementation that uses a fixed size buffer.
+ //*************************************************************************
+ template <typename T, const size_t MAX_SIZE_, typename TCompare = std::less<T> >
+ class set : public iset<T, TCompare>
+ {
+ public:
+
+ static const size_t MAX_SIZE = MAX_SIZE_;
+
+ //*************************************************************************
+ /// Default constructor.
+ //*************************************************************************
+ set()
+ : iset<T, TCompare>(node_pool, MAX_SIZE)
+ {
+ iset<T, TCompare>::initialise();
+ }
+
+ //*************************************************************************
+ /// Copy constructor.
+ //*************************************************************************
+ explicit set(const set& other)
+ : iset<T, TCompare>(node_pool, MAX_SIZE)
+ {
+ iset<T, TCompare>::assign(other.cbegin(), other.cend());
+ }
+
+ //*************************************************************************
+ /// Constructor, from an iterator range.
+ ///\tparam TIterator The iterator type.
+ ///\param first The iterator to the first element.
+ ///\param last The iterator to the last element + 1.
+ //*************************************************************************
+ template <typename TIterator>
+ set(TIterator first, TIterator last)
+ : iset<T, TCompare>(node_pool, MAX_SIZE)
+ {
+ iset<T, TCompare>::assign(first, last);
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ set& operator = (const set& rhs)
+ {
+ // Skip if doing self assignment
+ if (this != &rhs)
+ {
+ iset<T, TCompare>::assign(rhs.cbegin(), rhs.cend());
+ }
+
+ return *this;
+ }
+
+ private:
+
+ /// The pool of data nodes used for the set.
+ pool<typename iset<T, TCompare>::Data_Node, MAX_SIZE> node_pool;
+ };
+
+}
+
+#endif
diff --git a/lib/etl/smallest.h b/lib/etl/smallest.h
new file mode 100644
index 0000000..6419c60
--- /dev/null
+++ b/lib/etl/smallest.h
@@ -0,0 +1,179 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_SMALLEST__
+#define __ETL_SMALLEST__
+
+#include <stdint.h>
+
+#include "integral_limits.h"
+
+///\defgroup smallest smallest
+///\ingroup utilities
+
+namespace etl
+{
+ //***************************************************************************
+ /// Template to determine the smallest type and size.
+ /// Supports up to 16 types.
+ /// Defines 'value_type' which is the type of the smallest parameter.
+ /// Defines 'size' which is the size of the smallest parameter.
+ ///\ingroup smallest
+ //***************************************************************************
+ template <typename T1, typename T2 = void, typename T3 = void, typename T4 = void,
+ typename T5 = void, typename T6 = void, typename T7 = void, typename T8 = void,
+ typename T9 = void, typename T10 = void, typename T11 = void, typename T12 = void,
+ typename T13 = void, typename T14 = void, typename T15 = void, typename T16 = void>
+ struct smallest_type
+ {
+ private:
+
+ // Declaration.
+ template <const bool Boolean, typename TrueType, typename FalseType>
+ struct choose_type;
+
+ // Specialisation for 'true'.
+ // Defines 'type' as 'TrueType'.
+ template <typename TrueType, typename FalseType>
+ struct choose_type<true, TrueType, FalseType>
+ {
+ typedef TrueType type;
+ };
+
+ // Specialisation for 'false'.
+ // Defines 'type' as 'FalseType'.
+ template <typename TrueType, typename FalseType>
+ struct choose_type<false, TrueType, FalseType>
+ {
+ typedef FalseType type;
+ };
+
+ public:
+
+ // Define 'smallest_other' as 'smallest_type' with all but the first parameter.
+ typedef typename smallest_type<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::type smallest_other;
+
+ // Set 'type' to be the smallest of the first parameter and any of the others.
+ // This is recursive.
+ typedef typename choose_type<(sizeof(T1) < sizeof(smallest_other)),// Boolean
+ T1, // TrueType
+ smallest_other> // FalseType
+ ::type type; // The smallest type of the two.
+
+ // The size of the smallest type.
+ enum
+ {
+ size = sizeof(type)
+ };
+ };
+
+ //***************************************************************************
+ // Specialisation for one template parameter.
+ //***************************************************************************
+ template <typename T1>
+ struct smallest_type <T1, void, void, void,
+ void, void, void, void,
+ void, void, void, void,
+ void, void, void, void>
+ {
+ typedef T1 type;
+
+ enum
+ {
+ size = sizeof(type)
+ };
+ };
+
+ namespace __private_smallest__
+ {
+ //*************************************************************************
+ // Determine the type to hold the number of bits based on the index.
+ //*************************************************************************
+ template <const int index>
+ struct best_fit_uint_type;
+
+ //*************************************************************************
+ // Less than or equal to 8 bits.
+ //*************************************************************************
+ template <>
+ struct best_fit_uint_type<0>
+ {
+ typedef uint_least8_t type;
+ };
+
+ //*************************************************************************
+ // 9 to 16 bits.
+ //*************************************************************************
+ template <>
+ struct best_fit_uint_type<1>
+ {
+ typedef uint_least16_t type;
+ };
+
+ //*************************************************************************
+ // 17 to 31 bits.
+ //*************************************************************************
+ template <>
+ struct best_fit_uint_type<2>
+ {
+ typedef uint_least32_t type;
+ };
+
+ //*************************************************************************
+ // Greater than 32 bits.
+ //*************************************************************************
+ template <>
+ struct best_fit_uint_type<3>
+ {
+ typedef uint_least64_t type;
+ };
+ }
+
+ //***************************************************************************
+ /// Template to determine the smallest unsigned int type that can contain a
+ /// value with the specified number of bits.
+ /// Defines 'type' which is the type of the smallest unsigned integer.
+ ///\ingroup smallest
+ //***************************************************************************
+ template <const size_t NBITS>
+ struct smallest_uint_for_bits
+ {
+ private:
+
+ // Determines the index of the best unsigned type for the required number of bits.
+ static const int TYPE_INDEX = ((NBITS > 8) ? 1 : 0) + ((NBITS > 16) ? 1 : 0) + ((NBITS > 32) ? 1 : 0);
+
+ public:
+
+ typedef typename __private_smallest__::best_fit_uint_type<TYPE_INDEX>::type type;
+ };
+}
+
+#endif
diff --git a/lib/etl/stack.h b/lib/etl/stack.h
new file mode 100644
index 0000000..9862401
--- /dev/null
+++ b/lib/etl/stack.h
@@ -0,0 +1,109 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_STACK__
+#define __ETL_STACK__
+
+#include <stddef.h>
+#include <stdint.h>
+#include <algorithm>
+
+#include "istack.h"
+#include "container.h"
+#include "alignment.h"
+#include "array.h"
+
+//*****************************************************************************
+///\defgroup stack stack
+/// A Last-in / first-out stack with the capacity defined at compile time,
+/// written in the STL style.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+ //***************************************************************************
+ ///\ingroup stack
+ /// A fixed capacity stack.
+ /// This stack does not suppo7rt concurrent access by different threads.
+ /// \tparam T The type this stack should support.
+ /// \tparam MAX_SIZE The maximum capacity of the stack.
+ //***************************************************************************
+ template <typename T, const size_t SIZE>
+ class stack : public istack<T>
+ {
+ public:
+
+ //*************************************************************************
+ /// Default constructor.
+ //*************************************************************************
+ stack()
+ : istack<T>(reinterpret_cast<T*>(&buffer[0]), SIZE)
+ {
+ }
+
+ //*************************************************************************
+ /// Copy constructor
+ //*************************************************************************
+ stack(const stack& rhs)
+ : istack<T>(reinterpret_cast<T*>(&buffer[0]), SIZE)
+ {
+ istack<T>::clone(rhs);
+ }
+
+ //*************************************************************************
+ /// Destructor.
+ //*************************************************************************
+ ~stack()
+ {
+ istack<T>::clear();
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ stack& operator = (const stack& rhs)
+ {
+ if (&rhs != this)
+ {
+ istack<T>::clone(rhs);
+ }
+
+ return *this;
+ }
+
+ private:
+
+ /// The unititialised buffer of T used in the stack.
+ typename etl::aligned_storage<sizeof(T), etl::alignment_of<T>::value>::type buffer[SIZE];
+ };
+}
+
+#endif
diff --git a/lib/etl/static_assert.h b/lib/etl/static_assert.h
new file mode 100644
index 0000000..575b9c2
--- /dev/null
+++ b/lib/etl/static_assert.h
@@ -0,0 +1,53 @@
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_STATIC_ASSERT__
+#define __ETL_STATIC_ASSERT__
+
+#include "platform.h"
+
+#if defined(ETL_COMPILER_MICROSOFT)
+ #define STATIC_ASSERT(Condition, Message) static_assert(Condition, Message)
+#elif defined(ETL_COMPILER_GCC)
+ #define STATIC_ASSERT(Condition, Message) static_assert(Condition, Message)
+#else
+ template <bool Condition>
+ struct STATIC_ASSERT_FAILED;
+
+ template <>
+ struct STATIC_ASSERT_FAILED<true> {};
+
+ #define ETL_FCAT(a,b) a##b
+ #define ETL_ACAT(a,b) ETL_FCAT(a,b)
+ #define STATIC_ASSERT(cond,msg) \
+ enum \
+ { ETL_ACAT(dummy,__LINE__)=sizeof(STATIC_ASSERT_FAILED<(bool)(cond)>) \
+ }
+#endif
+
+#endif
diff --git a/lib/etl/string.h b/lib/etl/string.h
new file mode 100644
index 0000000..3f5bfb8
--- /dev/null
+++ b/lib/etl/string.h
@@ -0,0 +1,189 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_STRING__
+#define __ETL_STRING__
+
+#include "platform.h"
+#include "basic_string.h"
+
+#if defined(ETL_COMPILER_MICROSOFT)
+ #undef min
+#endif
+
+namespace etl
+{
+ typedef ibasic_string<char> istring;
+
+ //***************************************************************************
+ /// A string implementation that uses a fixed size buffer.
+ ///\tparam MAX_SIZE_ The maximum number of elements that can be stored.
+ ///\ingroup string
+ //***************************************************************************
+ template <const size_t MAX_SIZE_>
+ class string : public istring
+ {
+ public:
+
+ typedef istring::value_type value_type;
+
+ static const size_t MAX_SIZE = MAX_SIZE_;
+
+ //*************************************************************************
+ /// Constructor.
+ //*************************************************************************
+ string()
+ : istring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+ {
+ istring::initialise();
+ }
+
+ //*************************************************************************
+ /// Copy constructor.
+ ///\param other The other string.
+ //*************************************************************************
+ string(const etl::string<MAX_SIZE_>& other)
+ : istring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+ {
+ istring::initialise();
+ istring::assign(other.begin(), other.end());
+ }
+
+ //*************************************************************************
+ /// From other string, position, length.
+ ///\param other The other string.
+ ///\param position The position of the first character.
+ ///\param length The number of characters. Default = npos.
+ //*************************************************************************
+ string(const etl::string<MAX_SIZE_>& other, size_t position, size_t length = npos)
+ : istring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+ {
+ ETL_ASSERT(position < other.size(), ETL_ERROR(string_out_of_bounds));
+
+ // Set the length to the exact amount.
+ length = (length > MAX_SIZE_) ? MAX_SIZE_ : length;
+
+ istring::initialise();
+ istring::assign(other.begin() + position, other.begin() + position + length);
+ }
+
+ //*************************************************************************
+ /// Constructor, from null terminated text.
+ ///\param text The initial text of the string.
+ //*************************************************************************
+ string(const value_type* text)
+ : istring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+ {
+ istring::initialise();
+ istring::assign(text, text + etl::char_traits<value_type>::length(text));
+ }
+
+ //*************************************************************************
+ /// Constructor, from null terminated text and count.
+ ///\param text The initial text of the string.
+ ///\param count The number of characters to copy.
+ //*************************************************************************
+ string(const value_type* text, size_t count)
+ : istring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+ {
+ istring::initialise();
+ istring::assign(text, text + count);
+ }
+
+ //*************************************************************************
+ /// Constructor, from initial size and value.
+ ///\param initialSize The initial size of the string.
+ ///\param value The value to fill the string with.
+ //*************************************************************************
+ string(size_t count, value_type c)
+ : istring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+ {
+ istring::initialise();
+ istring::resize(count, c);
+ }
+
+ //*************************************************************************
+ /// Constructor, from an iterator range.
+ ///\tparam TIterator The iterator type.
+ ///\param first The iterator to the first element.
+ ///\param last The iterator to the last element + 1.
+ //*************************************************************************
+ template <typename TIterator>
+ string(TIterator first, TIterator last)
+ : istring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+ {
+ istring::assign(first, last);
+ }
+
+ //*************************************************************************
+ /// Returns a sub-string.
+ ///\param position The position of the first character. Default = 0.
+ ///\param length The number of characters. Default = npos.
+ //*************************************************************************
+ etl::string<MAX_SIZE_> substr(size_t position = 0, size_t length = npos) const
+ {
+ etl::string<MAX_SIZE_> new_string;
+
+ if (position != size())
+ {
+ ETL_ASSERT(position < size(), ETL_ERROR(string_out_of_bounds));
+
+ length = std::min(length, size() - position);
+
+ new_string.assign(buffer + position, buffer + position + length);
+ }
+
+ return new_string;
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ string& operator = (const string& rhs)
+ {
+ if (&rhs != this)
+ {
+ istring::assign(rhs.cbegin(), rhs.cend());
+ }
+
+ return *this;
+ }
+
+ private:
+
+ value_type buffer[MAX_SIZE + 1];
+ };
+}
+
+#if defined(ETL_COMPILER_MICROSOFT)
+ #define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#endif
diff --git a/lib/etl/type_def.h b/lib/etl/type_def.h
new file mode 100644
index 0000000..66d6156
--- /dev/null
+++ b/lib/etl/type_def.h
@@ -0,0 +1,293 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_TYPE_DEF__
+#define __ETL_TYPE_DEF__
+
+namespace etl
+{
+ #define ETL_TYPEDEF(T, name) class name##_tag; typedef etl::type_def<name##_tag, T> name
+
+ //*************************************************************************
+ /// A template type to define strong typedefs.
+ /// Usage:
+ ///\code
+ /// // Short form.
+ /// ETL_TYPEDEF(int, mytype);
+ ///
+ /// // Long form.
+ /// class mytype_t_tag;
+ /// typedef etl::type_def<mytype_t_tag, int> mytype_t_tag;
+ ///\endcode
+ //*************************************************************************
+ template <typename TIdType, typename TValue>
+ class type_def
+ {
+ public:
+
+ typedef TValue value_type;
+ typedef TIdType id_type;
+
+ //*********************************************************************
+ type_def()
+ : value(TValue())
+ {
+ }
+
+ //*********************************************************************
+ explicit type_def(TValue value)
+ : value(value)
+ {
+ }
+
+ //*********************************************************************
+ type_def(const type_def& other)
+ : value(other.value)
+ {
+ }
+
+ //*********************************************************************
+ operator TValue() const
+ {
+ return value;
+ }
+
+ //*********************************************************************
+ type_def& operator ++()
+ {
+ ++value;
+ return *this;
+ }
+
+ //*********************************************************************
+ type_def operator ++(int)
+ {
+ type_def temp(*this);
+ type_def::operator ++();
+ return temp;
+ }
+
+ //*********************************************************************
+ type_def& operator --()
+ {
+ --value;
+ return *this;
+ }
+
+ //*********************************************************************
+ type_def operator --(int)
+ {
+ type_def temp(*this);
+ type_def::operator --();
+ return temp;
+ }
+
+ //*********************************************************************
+ type_def& operator +=(TValue rhs)
+ {
+ value += rhs;
+ return *this;
+ }
+
+ //*********************************************************************
+ type_def& operator +=(const type_def& rhs)
+ {
+ value += rhs.value;
+ return *this;
+ }
+
+ //*********************************************************************
+ type_def& operator -=(TValue rhs)
+ {
+ value -= rhs;
+ return *this;
+ }
+
+ //*********************************************************************
+ type_def& operator -=(const type_def& rhs)
+ {
+ value -= rhs.value;
+ return *this;
+ }
+
+ //*********************************************************************
+ type_def& operator *=(TValue rhs)
+ {
+ value *= rhs;
+ return *this;
+ }
+
+ //*********************************************************************
+ type_def& operator *=(const type_def& rhs)
+ {
+ value *= rhs.value;
+ return *this;
+ }
+
+ //*********************************************************************
+ type_def& operator /=(TValue rhs)
+ {
+ value /= rhs;
+ return *this;
+ }
+
+ //*********************************************************************
+ type_def& operator /=(const type_def& rhs)
+ {
+ value /= rhs.value;
+ return *this;
+ }
+
+ //*********************************************************************
+ type_def& operator %=(TValue rhs)
+ {
+ value %= rhs;
+ return *this;
+ }
+
+ //*********************************************************************
+ type_def& operator %=(const type_def& rhs)
+ {
+ value %= rhs.value;
+ return *this;
+ }
+
+ //*********************************************************************
+ type_def& operator &=(TValue rhs)
+ {
+ value &= rhs;
+ return *this;
+ }
+
+ //*********************************************************************
+ type_def& operator &=(const type_def& rhs)
+ {
+ value &= rhs.value;
+ return *this;
+ }
+
+ //*********************************************************************
+ type_def& operator |=(TValue rhs)
+ {
+ value |= rhs;
+ return *this;
+ }
+
+ //*********************************************************************
+ type_def& operator |=(const type_def& rhs)
+ {
+ value |= rhs.value;
+ return *this;
+ }
+
+ //*********************************************************************
+ type_def& operator ^=(TValue rhs)
+ {
+ value ^= rhs;
+ return *this;
+ }
+
+ //*********************************************************************
+ type_def& operator ^=(const type_def& rhs)
+ {
+ value ^= rhs.value;
+ return *this;
+ }
+
+ //*********************************************************************
+ type_def& operator <<=(TValue rhs)
+ {
+ value <<= rhs;
+ return *this;
+ }
+
+ //*********************************************************************
+ type_def& operator >>=(TValue rhs)
+ {
+ value >>= rhs;
+ return *this;
+ }
+
+ //*********************************************************************
+ type_def& operator =(const type_def& rhs)
+ {
+ value = rhs.value;
+ return *this;
+ }
+
+ //*********************************************************************
+ TValue get() const
+ {
+ return value;
+ }
+
+ //*********************************************************************
+ friend bool operator <(const type_def& lhs, const type_def& rhs)
+ {
+ return lhs.value < rhs.value;
+ }
+
+ //*********************************************************************
+ friend bool operator <=(const type_def& lhs, const type_def& rhs)
+ {
+ return lhs.value <= rhs.value;
+ }
+
+ //*********************************************************************
+ friend bool operator >(const type_def& lhs, const type_def& rhs)
+ {
+ return lhs.value > rhs.value;
+ }
+
+ //*********************************************************************
+ friend bool operator >=(const type_def& lhs, const type_def& rhs)
+ {
+ return lhs.value >= rhs.value;
+ }
+
+ //*********************************************************************
+ friend bool operator ==(const type_def& lhs, const type_def& rhs)
+ {
+ return lhs.value == rhs.value;
+ }
+
+ //*********************************************************************
+ friend bool operator !=(const type_def& lhs, const type_def& rhs)
+ {
+ return lhs.value != rhs.value;
+ }
+
+ private:
+
+ TValue value;
+ };
+}
+
+#endif
diff --git a/lib/etl/type_traits.h b/lib/etl/type_traits.h
new file mode 100644
index 0000000..bef809a
--- /dev/null
+++ b/lib/etl/type_traits.h
@@ -0,0 +1,371 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_TYPE_TRAITS__
+#define __ETL_TYPE_TRAITS__
+
+#include <stddef.h>
+
+#include "platform.h"
+#include "nullptr.h"
+
+///\defgroup type_traits type_traits
+/// A set of type traits definitions for compilers that do not support the standard header.
+/// \ingroup utilities
+
+namespace etl
+{
+ /// integral_constant
+ ///\ingroup type_traits
+ template <typename T, const T VALUE>
+ struct integral_constant
+ {
+ static const T value = VALUE;
+
+ typedef T value_type;
+ typedef integral_constant<T, VALUE> type;
+
+ operator value_type() const
+ {
+ return value;
+ }
+ };
+
+ /// integral_constant specialisations
+ ///\ingroup type_traits
+ typedef integral_constant<bool, false> false_type;
+ typedef integral_constant<bool, true> true_type;
+
+ /// remove_reference
+ ///\ingroup type_traits
+ template <typename T> struct remove_reference { typedef T type; };
+ template <typename T> struct remove_reference<T&> { typedef T type; };
+
+ /// add_reference
+ ///\ingroup type_traits
+ template <typename T> struct add_reference { typedef T& type; };
+ template <typename T> struct add_reference<T&> { typedef T& type; };
+
+ /// remove_pointer
+ ///\ingroup type_traits
+ template <typename T> struct remove_pointer { typedef T type; };
+ template <typename T> struct remove_pointer<T*> { typedef T type; };
+
+ /// add_pointer
+ ///\ingroup type_traits
+ template <typename T> struct add_pointer { typedef typename remove_reference<T>::type* type; };
+
+ /// is_const
+ ///\ingroup type_traits
+ template <typename T> struct is_const : false_type {};
+ template <typename T> struct is_const<const T> : true_type {};
+ template <typename T> struct is_const<const volatile T> : true_type {};
+
+ /// remove_const
+ ///\ingroup type_traits
+ template <typename T> struct remove_const { typedef T type; };
+ template <typename T> struct remove_const<const T> { typedef T type; };
+
+ /// add_const
+ ///\ingroup type_traits
+ template <typename T> struct add_const { typedef const T type; };
+ template <typename T> struct add_const<const T> { typedef const T type; };
+
+ /// is_volatile
+ ///\ingroup type_traits
+ template <typename T> struct is_volatile : false_type {};
+ template <typename T> struct is_volatile<volatile T> : true_type {};
+ template <typename T> struct is_volatile<const volatile T> : true_type {};
+
+ /// remove_volatile
+ ///\ingroup type_traits
+ template <typename T> struct remove_volatile { typedef T type; };
+ template <typename T> struct remove_volatile<volatile T> { typedef T type; };
+
+ /// add_volatile
+ ///\ingroup type_traits
+ template <typename T> struct add_volatile { typedef volatile T type; };
+ template <typename T> struct add_volatile<volatile T> { typedef volatile T type; };
+
+ /// remove_cv
+ ///\ingroup type_traits
+ template <typename T> struct remove_cv
+ {
+ typedef typename remove_volatile<typename remove_const<T>::type>::type type;
+ };
+
+ /// add_cv
+ ///\ingroup type_traits
+ template <typename T> struct add_cv
+ {
+ typedef typename add_volatile<typename add_const<T>::type>::type type;
+ };
+
+ /// is_integral
+ ///\ingroup type_traits
+ template <typename T> struct is_integral : false_type {};
+ template <> struct is_integral<bool> : true_type {};
+ template <> struct is_integral<char> : true_type {};
+ template <> struct is_integral<unsigned char> : true_type {};
+ template <> struct is_integral<signed char> : true_type {};
+ template <> struct is_integral<wchar_t> : true_type {};
+ template <> struct is_integral<short> : true_type {};
+ template <> struct is_integral<unsigned short> : true_type {};
+ template <> struct is_integral<int> : true_type {};
+ template <> struct is_integral<unsigned int> : true_type {};
+ template <> struct is_integral<long> : true_type {};
+ template <> struct is_integral<unsigned long> : true_type {};
+ template <> struct is_integral<long long> : true_type {};
+ template <> struct is_integral<unsigned long long> : true_type {};
+ template <typename T> struct is_integral<const T> : is_integral<T> {};
+ template <typename T> struct is_integral<volatile T> : is_integral<T> {};
+ template <typename T> struct is_integral<const volatile T> : is_integral<T> {};
+
+
+ /// is_signed
+ ///\ingroup type_traits
+ template <typename T> struct is_signed : false_type {};
+ template <> struct is_signed<char> : integral_constant<bool, (char(255) < 0)> {};
+ template <> struct is_signed<wchar_t> : public etl::integral_constant<bool, static_cast<bool>(wchar_t(-1) < wchar_t(0))> {};
+ template <> struct is_signed<signed char> : true_type {};
+ template <> struct is_signed<short> : true_type {};
+ template <> struct is_signed<int> : true_type {};
+ template <> struct is_signed<long> : true_type {};
+ template <> struct is_signed<long long> : true_type {};
+ template <> struct is_signed<float> : true_type{};
+ template <> struct is_signed<double> : true_type{};
+ template <> struct is_signed<long double> : true_type{};
+ template <typename T> struct is_signed<const T> : is_signed<T> {};
+ template <typename T> struct is_signed<volatile T> : is_signed<T> {};
+ template <typename T> struct is_signed<const volatile T> : is_signed<T> {};
+
+ /// is_unsigned
+ ///\ingroup type_traits
+ template <typename T> struct is_unsigned : false_type {};
+ template <> struct is_unsigned<bool> : true_type {};
+ template <> struct is_unsigned<char> : integral_constant<bool, (char(255) > 0)> {};
+ template <> struct is_unsigned<unsigned char> : true_type {};
+ template <> struct is_unsigned<wchar_t> : public etl::integral_constant<bool, (wchar_t(-1) > wchar_t(0))> {};
+ template <> struct is_unsigned<unsigned short> : true_type {};
+ template <> struct is_unsigned<unsigned int> : true_type {};
+ template <> struct is_unsigned<unsigned long> : true_type {};
+ template <> struct is_unsigned<unsigned long long> : true_type {};
+ template <typename T> struct is_unsigned<const T> : is_unsigned<T> {};
+ template <typename T> struct is_unsigned<volatile T> : is_unsigned<T> {};
+ template <typename T> struct is_unsigned<const volatile T> : is_unsigned<T> {};
+
+ /// is_floating_point
+ ///\ingroup type_traits
+ template <typename T> struct is_floating_point : false_type {};
+ template <> struct is_floating_point<float> : true_type {};
+ template <> struct is_floating_point<double> : true_type {};
+ template <> struct is_floating_point<long double> : true_type {};
+ template <typename T> struct is_floating_point<const T> : is_floating_point<T> {};
+ template <typename T> struct is_floating_point<volatile T> : is_floating_point<T> {};
+ template <typename T> struct is_floating_point<const volatile T> : is_floating_point<T> {};
+
+ /// is_same
+ ///\ingroup type_traits
+ template <typename T1, typename T2> struct is_same : public false_type {};
+ template <typename T> struct is_same<T, T> : public true_type {};
+
+ /// is_void
+ ///\ingroup type_traits
+ template<typename T> struct is_void : false_type {};
+ template<> struct is_void<void> : true_type {};
+
+ /// is_arithmetic
+ ///\ingroup type_traits
+ template<typename T> struct is_arithmetic : integral_constant<bool, is_integral<T>::value || is_floating_point<T>::value> {};
+
+ /// is_fundamental
+ ///\ingroup type_traits
+ template <typename T> struct is_fundamental : integral_constant<bool, is_arithmetic<T>::value ||
+ is_void<T>::value ||
+ is_same<std::nullptr_t,
+ typename remove_cv<T>::type>::value> {};
+
+ /// is_compound
+ ///\ingroup type_traits
+ template <typename T> struct is_compound : integral_constant<bool, !is_fundamental<T>::value> {};
+
+ /// is_array
+ ///\ingroup type_traits
+ template <typename T> struct is_array : false_type {};
+ template <typename T> struct is_array<T[]> : true_type {};
+ template <typename T, size_t MAXN> struct is_array<T[MAXN]> : true_type {};
+
+ /// is_pointer
+ ///\ingroup type_traits
+ template <typename T> struct is_pointer : false_type {};
+ template <typename T> struct is_pointer<T*> : true_type {};
+
+ /// is_reference
+ ///\ingroup type_traits
+ template <typename T> struct is_reference : false_type {};
+ template <typename T> struct is_reference<T&> : true_type {};
+
+ /// conditional
+ ///\ingroup type_traits
+ template <bool B, typename T, typename F> struct conditional { typedef T type; };
+ template <typename T, typename F> struct conditional<false, T, F> { typedef F type; };
+
+ /// make_signed
+ ///\ingroup type_traits
+ template <typename T> struct make_signed { typedef T type; };
+ template <> struct make_signed<char> { typedef signed char type; };
+ template <> struct make_signed<unsigned char> { typedef signed char type; };
+#if defined(ETL_COMPILER_GCC)
+ template <> struct make_signed<wchar_t>
+ {
+ typedef wchar_t type;
+ };
+#else
+ template <> struct make_signed<wchar_t>
+ {
+ typedef etl::conditional<sizeof(wchar_t) == sizeof(short), short,
+ etl::conditional<sizeof(wchar_t) == sizeof(int), int,
+ etl::conditional<sizeof(wchar_t) == sizeof(long), long, void>::type>::type>::type type;
+ };
+#endif
+ template <> struct make_signed<unsigned short> { typedef short type; };
+ template <> struct make_signed<unsigned int> { typedef int type; };
+ template <> struct make_signed<unsigned long> { typedef long type; };
+ template <> struct make_signed<unsigned long long> { typedef long long type; };
+ template <typename T> struct make_signed<const T> : add_const<typename make_signed<T>::type> {};
+ template <typename T> struct make_signed<volatile T> : add_volatile<typename make_signed<T>::type> {};
+ template <typename T> struct make_signed<const volatile T> : add_const<typename add_volatile<typename make_signed<T>::type>::type> {};
+
+ /// make_unsigned
+ ///\ingroup type_traits
+ template <typename T> struct make_unsigned { typedef T type; };
+ template <> struct make_unsigned<char> { typedef unsigned char type; };
+ template <> struct make_unsigned<signed char> { typedef unsigned char type; };
+ template <> struct make_unsigned<short> { typedef unsigned short type; };
+#if defined(ETL_COMPILER_GCC) && !defined(ETL_PLATFORM_LINUX)
+ template <> struct make_unsigned<wchar_t>
+ {
+ typedef wchar_t type;
+ };
+#else
+ template <> struct make_unsigned<wchar_t>
+ {
+ typedef etl::conditional<sizeof(wchar_t) == sizeof(unsigned short), unsigned short,
+ etl::conditional<sizeof(wchar_t) == sizeof(unsigned int), unsigned int,
+ etl::conditional<sizeof(wchar_t) == sizeof(unsigned long), unsigned long, void>::type>::type>::type type;
+ };
+#endif
+ template <> struct make_unsigned<int> { typedef unsigned int type; };
+ template <> struct make_unsigned<long> { typedef unsigned long type; };
+ template <> struct make_unsigned<long long> { typedef unsigned long long type; };
+ template <typename T> struct make_unsigned<const T> : add_const<typename make_unsigned<T>::type> {};
+ template <typename T> struct make_unsigned<volatile T> : add_volatile<typename make_unsigned<T>::type> {};
+ template <typename T> struct make_unsigned<const volatile T> : add_const<typename add_volatile<typename make_unsigned<T>::type>::type> {};
+
+ /// enable_if
+ ///\ingroup type_traits
+ template <bool B, typename T = void> struct enable_if {};
+ template <typename T> struct enable_if<true, T> { typedef T type; };
+
+ /// extent
+ ///\ingroup type_traits
+ template <typename T, size_t MAXN = 0>
+ struct extent : integral_constant<size_t, 0> {};
+
+ template <typename T>
+ struct extent<T[], 0> : integral_constant<size_t, 0> {};
+
+ template <typename T, size_t MAXN>
+ struct extent<T[], MAXN> : integral_constant<size_t, extent<T, MAXN - 1>::value> {};
+
+ template <typename T, size_t MAXN>
+ struct extent<T[MAXN], 0> : integral_constant<size_t, MAXN> {};
+
+ template <typename T, size_t I, size_t MAXN>
+ struct extent<T[I], MAXN> : integral_constant<size_t, extent<T, MAXN - 1>::value> {};
+
+ /// remove_extent
+ ///\ingroup type_traits
+ template <typename T> struct remove_extent { typedef T type; };
+ template <typename T> struct remove_extent<T[]> { typedef T type; };
+ template <typename T, size_t MAXN> struct remove_extent<T[MAXN]> { typedef T type;};
+
+ /// remove_all_extents
+ ///\ingroup type_traits
+ template <typename T> struct remove_all_extents { typedef T type;};
+ template <typename T> struct remove_all_extents<T[]> { typedef typename remove_all_extents<T>::type type; };
+ template <typename T, size_t MAXN> struct remove_all_extents<T[MAXN]> { typedef typename remove_all_extents<T>::type type; };
+
+ /// rank
+ ///\ingroup type_traits
+ template <typename T>struct rank : integral_constant<size_t, 0> {};
+ template <typename T> struct rank<T[]> : public integral_constant<size_t, rank<T>::value + 1> {};
+ template <typename T, size_t MAXN> struct rank<T[MAXN]> : public integral_constant<size_t, rank<T>::value + 1> {};
+
+ /// decay
+ ///\ingroup type_traits
+ template <typename T>
+ struct decay
+ {
+ typedef typename etl::remove_reference<T>::type U;
+ typedef typename etl::conditional<etl::is_array<U>::value,
+ typename etl::remove_extent<U>::type*,
+ typename etl::remove_cv<U>::type>::type type;
+ };
+
+ /// Alignment templates.
+ /// These require compiler specific intrinsics.
+ ///\ingroup type_traits
+#ifdef ETL_COMPILER_MICROSOFT
+ template <typename T> struct alignment_of : integral_constant<size_t, size_t(__alignof(T))> {};
+#endif
+
+#ifdef ETL_COMPILER_GCC
+ template <typename T> struct alignment_of : integral_constant<size_t, size_t(__alignof__(T))> {};
+#endif
+
+#ifdef ETL_COMPILER_KEIL
+ template <typename T> struct alignment_of : integral_constant<size_t, size_t(__alignof__(T))> {};
+#endif
+
+#ifdef ETL_COMPILER_IAR
+ template <typename T> struct alignment_of : integral_constant<size_t, size_t(__ALIGNOF__(T))> {};
+#endif
+
+#ifdef ETL_COMPILER_TI_MSP430
+ template <typename T> struct alignment_of : integral_constant<size_t, size_t(__ALIGNOF__(T))> {};
+#endif
+
+ /// Specialisation of 'alignment_of' for 'void'.
+ ///\ingroup type_traits
+ template <> struct alignment_of<void> : integral_constant <size_t, 0>{};
+}
+
+#endif
diff --git a/lib/etl/u16string.h b/lib/etl/u16string.h
new file mode 100644
index 0000000..a7ca2b5
--- /dev/null
+++ b/lib/etl/u16string.h
@@ -0,0 +1,189 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_U16STRING__
+#define __ETL_U16STRING__
+
+#include "platform.h"
+#include "basic_string.h"
+
+#if defined(ETL_COMPILER_MICROSOFT)
+ #undef min
+#endif
+
+namespace etl
+{
+ typedef ibasic_string<char16_t> iu16string;
+
+ //***************************************************************************
+ /// A u16string implementation that uses a fixed size buffer.
+ ///\tparam MAX_SIZE_ The maximum number of elements that can be stored.
+ ///\ingroup u16string
+ //***************************************************************************
+ template <const size_t MAX_SIZE_>
+ class u16string : public iu16string
+ {
+ public:
+
+ typedef iu16string::value_type value_type;
+
+ static const size_t MAX_SIZE = MAX_SIZE_;
+
+ //*************************************************************************
+ /// Constructor.
+ //*************************************************************************
+ u16string()
+ : iu16string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+ {
+ iu16string::initialise();
+ }
+
+ //*************************************************************************
+ /// Copy constructor.
+ ///\param other The other string.
+ //*************************************************************************
+ u16string(const etl::u16string<MAX_SIZE_>& other)
+ : iu16string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+ {
+ iu16string::initialise();
+ iu16string::assign(other.begin(), other.end());
+ }
+
+ //*************************************************************************
+ /// From other string, position, length.
+ ///\param other The other string.
+ ///\param position The position of the first character.
+ ///\param length The number of characters. Default = npos.
+ //*************************************************************************
+ u16string(const etl::u16string<MAX_SIZE_>& other, size_t position, size_t length = npos)
+ : iu16string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+ {
+ ETL_ASSERT(position < other.size(), ETL_ERROR(string_out_of_bounds));
+
+ // Set the length to the exact amount.
+ length = (length > MAX_SIZE_) ? MAX_SIZE_ : length;
+
+ iu16string::initialise();
+ iu16string::assign(other.begin() + position, other.begin() + position + length);
+ }
+
+ //*************************************************************************
+ /// Constructor, from null terminated text.
+ ///\param text The initial text of the u16string.
+ //*************************************************************************
+ u16string(const value_type* text)
+ : iu16string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+ {
+ iu16string::initialise();
+ iu16string::assign(text, text + etl::char_traits<value_type>::length(text));
+ }
+
+ //*************************************************************************
+ /// Constructor, from null terminated text and count.
+ ///\param text The initial text of the u16string.
+ ///\param count The number of characters to copy.
+ //*************************************************************************
+ u16string(const value_type* text, size_t count)
+ : iu16string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+ {
+ iu16string::initialise();
+ iu16string::assign(text, text + count);
+ }
+
+ //*************************************************************************
+ /// Constructor, from initial size and value.
+ ///\param initialSize The initial size of the u16string.
+ ///\param value The value to fill the u16string with.
+ //*************************************************************************
+ u16string(size_t count, value_type c)
+ : iu16string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+ {
+ iu16string::initialise();
+ iu16string::resize(count, c);
+ }
+
+ //*************************************************************************
+ /// Constructor, from an iterator range.
+ ///\tparam TIterator The iterator type.
+ ///\param first The iterator to the first element.
+ ///\param last The iterator to the last element + 1.
+ //*************************************************************************
+ template <typename TIterator>
+ u16string(TIterator first, TIterator last)
+ : iu16string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+ {
+ iu16string::assign(first, last);
+ }
+
+ //*************************************************************************
+ /// Returns a sub-string.
+ ///\param position The position of the first character. Default = 0.
+ ///\param length The number of characters. Default = npos.
+ //*************************************************************************
+ etl::u16string<MAX_SIZE_> substr(size_t position = 0, size_t length = npos) const
+ {
+ etl::u16string<MAX_SIZE_> new_string;
+
+ if (position != size())
+ {
+ ETL_ASSERT(position < size(), ETL_ERROR(string_out_of_bounds));
+
+ length = std::min(length, size() - position);
+
+ new_string.assign(buffer + position, buffer + position + length);
+ }
+
+ return new_string;
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ u16string& operator = (const u16string& rhs)
+ {
+ if (&rhs != this)
+ {
+ iu16string::assign(rhs.cbegin(), rhs.cend());
+ }
+
+ return *this;
+ }
+
+ private:
+
+ value_type buffer[MAX_SIZE + 1];
+ };
+}
+
+#if defined(ETL_COMPILER_MICROSOFT)
+ #define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#endif
diff --git a/lib/etl/u32string.h b/lib/etl/u32string.h
new file mode 100644
index 0000000..5890f1c
--- /dev/null
+++ b/lib/etl/u32string.h
@@ -0,0 +1,189 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_U32STRING__
+#define __ETL_U32STRING__
+
+#include "platform.h"
+#include "basic_string.h"
+
+#if defined(ETL_COMPILER_MICROSOFT)
+ #undef min
+#endif
+
+namespace etl
+{
+ typedef ibasic_string<char32_t> iu32string;
+
+ //***************************************************************************
+ /// A u32string implementation that uses a fixed size buffer.
+ ///\tparam MAX_SIZE_ The maximum number of elements that can be stored.
+ ///\ingroup u32string
+ //***************************************************************************
+ template <const size_t MAX_SIZE_>
+ class u32string : public iu32string
+ {
+ public:
+
+ typedef iu32string::value_type value_type;
+
+ static const size_t MAX_SIZE = MAX_SIZE_;
+
+ //*************************************************************************
+ /// Constructor.
+ //*************************************************************************
+ u32string()
+ : iu32string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+ {
+ iu32string::initialise();
+ }
+
+ //*************************************************************************
+ /// Copy constructor.
+ ///\param other The other string.
+ //*************************************************************************
+ u32string(const etl::u32string<MAX_SIZE_>& other)
+ : iu32string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+ {
+ iu32string::initialise();
+ iu32string::assign(other.begin(), other.end());
+ }
+
+ //*************************************************************************
+ /// From other string, position, length.
+ ///\param other The other string.
+ ///\param position The position of the first character.
+ ///\param length The number of characters. Default = npos.
+ //*************************************************************************
+ u32string(const etl::u32string<MAX_SIZE_>& other, size_t position, size_t length = npos)
+ : iu32string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+ {
+ ETL_ASSERT(position < other.size(), ETL_ERROR(string_out_of_bounds));
+
+ // Set the length to the exact amount.
+ length = (length > MAX_SIZE_) ? MAX_SIZE_ : length;
+
+ iu32string::initialise();
+ iu32string::assign(other.begin() + position, other.begin() + position + length);
+ }
+
+ //*************************************************************************
+ /// Constructor, from null terminated text.
+ ///\param text The initial text of the u32string.
+ //*************************************************************************
+ u32string(const value_type* text)
+ : iu32string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+ {
+ iu32string::initialise();
+ iu32string::assign(text, text + etl::char_traits<value_type>::length(text));
+ }
+
+ //*************************************************************************
+ /// Constructor, from null terminated text and count.
+ ///\param text The initial text of the u32string.
+ ///\param count The number of characters to copy.
+ //*************************************************************************
+ u32string(const value_type* text, size_t count)
+ : iu32string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+ {
+ iu32string::initialise();
+ iu32string::assign(text, text + count);
+ }
+
+ //*************************************************************************
+ /// Constructor, from initial size and value.
+ ///\param initialSize The initial size of the u32string.
+ ///\param value The value to fill the u32string with.
+ //*************************************************************************
+ u32string(size_t count, value_type c)
+ : iu32string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+ {
+ iu32string::initialise();
+ iu32string::resize(count, c);
+ }
+
+ //*************************************************************************
+ /// Constructor, from an iterator range.
+ ///\tparam TIterator The iterator type.
+ ///\param first The iterator to the first element.
+ ///\param last The iterator to the last element + 1.
+ //*************************************************************************
+ template <typename TIterator>
+ u32string(TIterator first, TIterator last)
+ : iu32string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+ {
+ iu32string::assign(first, last);
+ }
+
+ //*************************************************************************
+ /// Returns a sub-string.
+ ///\param position The position of the first character. Default = 0.
+ ///\param length The number of characters. Default = npos.
+ //*************************************************************************
+ etl::u32string<MAX_SIZE_> substr(size_t position = 0, size_t length = npos) const
+ {
+ etl::u32string<MAX_SIZE_> new_string;
+
+ if (position != size())
+ {
+ ETL_ASSERT(position < size(), ETL_ERROR(string_out_of_bounds));
+
+ length = std::min(length, size() - position);
+
+ new_string.assign(buffer + position, buffer + position + length);
+ }
+
+ return new_string;
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ u32string& operator = (const u32string& rhs)
+ {
+ if (&rhs != this)
+ {
+ iu32string::assign(rhs.cbegin(), rhs.cend());
+ }
+
+ return *this;
+ }
+
+ private:
+
+ value_type buffer[MAX_SIZE + 1];
+ };
+}
+
+#if defined(ETL_COMPILER_MICROSOFT)
+ #define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#endif
diff --git a/lib/etl/unordered_map.h b/lib/etl/unordered_map.h
new file mode 100644
index 0000000..e4c1f1e
--- /dev/null
+++ b/lib/etl/unordered_map.h
@@ -0,0 +1,123 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_UNORDERED_MAP__
+#define __ETL_UNORDERED_MAP__
+
+#include <stddef.h>
+#include <iterator>
+#include <functional>
+
+#include "iunordered_map.h"
+#include "container.h"
+#include "pool.h"
+#include "vector.h"
+#include "intrusive_forward_list.h"
+#include "hash.h"
+
+//*****************************************************************************
+///\defgroup unordered_map unordered_map
+/// A unordered_map with the capacity defined at compile time.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+ //*************************************************************************
+ /// A templated unordered_map implementation that uses a fixed size buffer.
+ //*************************************************************************
+ template <typename TKey, typename TValue, const size_t MAX_SIZE_, typename THash = etl::hash<TKey>, typename TKeyEqual = std::equal_to<TKey> >
+ class unordered_map : public iunordered_map<TKey, TValue, THash, TKeyEqual>
+ {
+ private:
+
+ typedef iunordered_map<TKey, TValue, THash, TKeyEqual> base;
+
+ public:
+
+ static const size_t MAX_SIZE = MAX_SIZE_;
+
+ //*************************************************************************
+ /// Default constructor.
+ //*************************************************************************
+ unordered_map()
+ : base(node_pool, buckets)
+ {
+ base::initialise();
+ }
+
+ //*************************************************************************
+ /// Copy constructor.
+ //*************************************************************************
+ unordered_map(const unordered_map& other)
+ : base(node_pool, buckets)
+ {
+ base::assign(other.cbegin(), other.cend());
+ }
+
+ //*************************************************************************
+ /// Constructor, from an iterator range.
+ ///\tparam TIterator The iterator type.
+ ///\param first The iterator to the first element.
+ ///\param last The iterator to the last element + 1.
+ //*************************************************************************
+ template <typename TIterator>
+ unordered_map(TIterator first, TIterator last)
+ : base(node_pool, buckets)
+ {
+ base::assign(first, last);
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ unordered_map& operator = (const unordered_map& rhs)
+ {
+ // Skip if doing self assignment
+ if (this != &rhs)
+ {
+ base::assign(rhs.cbegin(), rhs.cend());
+ }
+
+ return *this;
+ }
+
+ private:
+
+ /// The pool of nodes used for the unordered_map.
+ etl::pool<typename base::node_t, MAX_SIZE> node_pool;
+
+ /// The buckets of node lists.
+ etl::vector<etl::intrusive_forward_list<typename base::node_t>, MAX_SIZE> buckets;
+ };
+
+}
+
+#endif
diff --git a/lib/etl/unordered_multimap.h b/lib/etl/unordered_multimap.h
new file mode 100644
index 0000000..14746fe
--- /dev/null
+++ b/lib/etl/unordered_multimap.h
@@ -0,0 +1,123 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_UNORDERED_MULTIMAP__
+#define __ETL_UNORDERED_MULTIMAP__
+
+#include <stddef.h>
+#include <iterator>
+#include <functional>
+
+#include "iunordered_multimap.h"
+#include "container.h"
+#include "pool.h"
+#include "vector.h"
+#include "intrusive_forward_list.h"
+#include "hash.h"
+
+//*****************************************************************************
+///\defgroup unordered_multimap unordered_multimap
+/// A unordered_multimap with the capacity defined at compile time.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+ //*************************************************************************
+ /// A templated unordered_multimap implementation that uses a fixed size buffer.
+ //*************************************************************************
+ template <typename TKey, typename TValue, const size_t MAX_SIZE_, typename THash = etl::hash<TKey>, typename TKeyEqual = std::equal_to<TKey> >
+ class unordered_multimap : public iunordered_multimap<TKey, TValue, THash, TKeyEqual>
+ {
+ private:
+
+ typedef iunordered_multimap<TKey, TValue, THash, TKeyEqual> base;
+
+ public:
+
+ static const size_t MAX_SIZE = MAX_SIZE_;
+
+ //*************************************************************************
+ /// Default constructor.
+ //*************************************************************************
+ unordered_multimap()
+ : base(node_pool, buckets)
+ {
+ base::initialise();
+ }
+
+ //*************************************************************************
+ /// Copy constructor.
+ //*************************************************************************
+ unordered_multimap(const unordered_multimap& other)
+ : base(node_pool, buckets)
+ {
+ base::assign(other.cbegin(), other.cend());
+ }
+
+ //*************************************************************************
+ /// Constructor, from an iterator range.
+ ///\tparam TIterator The iterator type.
+ ///\param first The iterator to the first element.
+ ///\param last The iterator to the last element + 1.
+ //*************************************************************************
+ template <typename TIterator>
+ unordered_multimap(TIterator first, TIterator last)
+ : base(node_pool, buckets)
+ {
+ base::assign(first, last);
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ unordered_multimap& operator = (const unordered_multimap& rhs)
+ {
+ // Skip if doing self assignment
+ if (this != &rhs)
+ {
+ base::assign(rhs.cbegin(), rhs.cend());
+ }
+
+ return *this;
+ }
+
+ private:
+
+ /// The pool of nodes used for the unordered_multimap.
+ etl::pool<typename base::node_t, MAX_SIZE> node_pool;
+
+ /// The buckets of node lists.
+ etl::vector<etl::intrusive_forward_list<typename base::node_t>, MAX_SIZE> buckets;
+ };
+
+}
+
+#endif
diff --git a/lib/etl/unordered_multiset.h b/lib/etl/unordered_multiset.h
new file mode 100644
index 0000000..c4e1ce3
--- /dev/null
+++ b/lib/etl/unordered_multiset.h
@@ -0,0 +1,123 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_UNORDERED_MULTISET__
+#define __ETL_UNORDERED_MULTISET__
+
+#include <stddef.h>
+#include <iterator>
+#include <functional>
+
+#include "iunordered_multiset.h"
+#include "container.h"
+#include "pool.h"
+#include "vector.h"
+#include "intrusive_forward_list.h"
+#include "hash.h"
+
+//*****************************************************************************
+///\defgroup unordered_multiset unordered_multiset
+/// A unordered_multiset with the capacity defined at compile time.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+ //*************************************************************************
+ /// A templated unordered_multiset implementation that uses a fixed size buffer.
+ //*************************************************************************
+ template <typename TKey, const size_t MAX_SIZE_, typename THash = etl::hash<TKey>, typename TKeyEqual = std::equal_to<TKey> >
+ class unordered_multiset : public iunordered_multiset<TKey, THash, TKeyEqual>
+ {
+ private:
+
+ typedef iunordered_multiset<TKey, THash, TKeyEqual> base;
+
+ public:
+
+ static const size_t MAX_SIZE = MAX_SIZE_;
+
+ //*************************************************************************
+ /// Default constructor.
+ //*************************************************************************
+ unordered_multiset()
+ : base(node_pool, buckets)
+ {
+ base::initialise();
+ }
+
+ //*************************************************************************
+ /// Copy constructor.
+ //*************************************************************************
+ unordered_multiset(const unordered_multiset& other)
+ : base(node_pool, buckets)
+ {
+ base::assign(other.cbegin(), other.cend());
+ }
+
+ //*************************************************************************
+ /// Constructor, from an iterator range.
+ ///\tparam TIterator The iterator type.
+ ///\param first The iterator to the first element.
+ ///\param last The iterator to the last element + 1.
+ //*************************************************************************
+ template <typename TIterator>
+ unordered_multiset(TIterator first, TIterator last)
+ : base(node_pool, buckets)
+ {
+ base::assign(first, last);
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ unordered_multiset& operator = (const unordered_multiset& rhs)
+ {
+ // Skip if doing self assignment
+ if (this != &rhs)
+ {
+ base::assign(rhs.cbegin(), rhs.cend());
+ }
+
+ return *this;
+ }
+
+ private:
+
+ /// The pool of nodes used for the unordered_multiset.
+ etl::pool<typename base::node_t, MAX_SIZE> node_pool;
+
+ /// The buckets of node lists.
+ etl::vector<etl::intrusive_forward_list<typename base::node_t>, MAX_SIZE> buckets;
+ };
+
+}
+
+#endif
diff --git a/lib/etl/unordered_set.h b/lib/etl/unordered_set.h
new file mode 100644
index 0000000..e917156
--- /dev/null
+++ b/lib/etl/unordered_set.h
@@ -0,0 +1,123 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_UNORDERED_SET__
+#define __ETL_UNORDERED_SET__
+
+#include <stddef.h>
+#include <iterator>
+#include <functional>
+
+#include "iunordered_set.h"
+#include "container.h"
+#include "pool.h"
+#include "vector.h"
+#include "intrusive_forward_list.h"
+#include "hash.h"
+
+//*****************************************************************************
+///\defgroup unordered_set unordered_set
+/// A unordered_set with the capacity defined at compile time.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+ //*************************************************************************
+ /// A templated unordered_set implementation that uses a fixed size buffer.
+ //*************************************************************************
+ template <typename TKey, const size_t MAX_SIZE_, typename THash = etl::hash<TKey>, typename TKeyEqual = std::equal_to<TKey> >
+ class unordered_set : public iunordered_set<TKey, THash, TKeyEqual>
+ {
+ private:
+
+ typedef iunordered_set<TKey, THash, TKeyEqual> base;
+
+ public:
+
+ static const size_t MAX_SIZE = MAX_SIZE_;
+
+ //*************************************************************************
+ /// Default constructor.
+ //*************************************************************************
+ unordered_set()
+ : base(node_pool, buckets)
+ {
+ base::initialise();
+ }
+
+ //*************************************************************************
+ /// Copy constructor.
+ //*************************************************************************
+ unordered_set(const unordered_set& other)
+ : base(node_pool, buckets)
+ {
+ base::assign(other.cbegin(), other.cend());
+ }
+
+ //*************************************************************************
+ /// Constructor, from an iterator range.
+ ///\tparam TIterator The iterator type.
+ ///\param first The iterator to the first element.
+ ///\param last The iterator to the last element + 1.
+ //*************************************************************************
+ template <typename TIterator>
+ unordered_set(TIterator first, TIterator last)
+ : base(node_pool, buckets)
+ {
+ base::assign(first, last);
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ unordered_set& operator = (const unordered_set& rhs)
+ {
+ // Skip if doing self assignment
+ if (this != &rhs)
+ {
+ base::assign(rhs.cbegin(), rhs.cend());
+ }
+
+ return *this;
+ }
+
+ private:
+
+ /// The pool of nodes used for the unordered_set.
+ etl::pool<typename base::node_t, MAX_SIZE> node_pool;
+
+ /// The buckets of node lists.
+ etl::vector<etl::intrusive_forward_list<typename base::node_t>, MAX_SIZE> buckets;
+ };
+
+}
+
+#endif
diff --git a/lib/etl/variant.h b/lib/etl/variant.h
new file mode 100644
index 0000000..2e8522e
--- /dev/null
+++ b/lib/etl/variant.h
@@ -0,0 +1,935 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_VARIANT__
+#define __ETL_VARIANT__
+
+#include <stdint.h>
+
+#include "platform.h"
+#include "array.h"
+#include "largest.h"
+#include "exception.h"
+#include "type_traits.h"
+#include "integral_limits.h"
+#include "static_assert.h"
+#include "alignment.h"
+#include "error_handler.h"
+#include "largest.h"
+
+#if defined(ETL_COMPILER_KEIL)
+ #pragma diag_suppress 940
+ #pragma diag_suppress 111
+#endif
+
+#undef ETL_FILE
+#define ETL_FILE "24"
+
+//*****************************************************************************
+///\defgroup variant variant
+/// A class that can contain one a several specified types in a type safe manner.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+ namespace __private_variant__
+ {
+ //*************************************************************************
+ /// Placeholder for unused template parameters.
+ /// This class is never instantiated.
+ //*************************************************************************
+ template <const size_t ID>
+ struct no_type
+ {
+ };
+ }
+
+ //***************************************************************************
+ /// Base exception for the variant class.
+ ///\ingroup variant
+ //***************************************************************************
+ class variant_exception : public exception
+ {
+ public:
+ variant_exception(string_type what, string_type file_name, numeric_type line_number)
+ : exception(what, file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// 'Unsupported type' exception for the variant class.
+ ///\ingroup variant
+ //***************************************************************************
+ class variant_incorrect_type_exception : public variant_exception
+ {
+ public:
+ variant_incorrect_type_exception(string_type file_name, numeric_type line_number)
+ : variant_exception(ETL_ERROR_TEXT("variant: unsupported type", ETL_FILE"A"), file_name, line_number)
+ {
+ }
+ };
+
+ //***************************************************************************
+ /// A template class that can store any of the types defined in the template parameter list.
+ /// Supports up to 8 types.
+ ///\ingroup variant
+ //***************************************************************************
+ template <typename T1,
+ typename T2 = __private_variant__::no_type<2>,
+ typename T3 = __private_variant__::no_type<3>,
+ typename T4 = __private_variant__::no_type<4>,
+ typename T5 = __private_variant__::no_type<5>,
+ typename T6 = __private_variant__::no_type<6>,
+ typename T7 = __private_variant__::no_type<7>,
+ typename T8 = __private_variant__::no_type<8> >
+ class variant
+ {
+ private:
+
+ // All types of variant are friends.
+ template <typename U1, typename U2, typename U3, typename U4, typename U5, typename U6, typename U7, typename U8>
+ friend class variant;
+
+ //***************************************************************************
+ /// The largest type.
+ //***************************************************************************
+ typedef typename largest_type<T1, T2, T3, T4, T5, T6, T7, T8>::type largest_t;
+
+ //***************************************************************************
+ /// The largest alignment.
+ //***************************************************************************
+ static const size_t ALIGNMENT = etl::largest_alignment<T1, T2, T3, T4, T5, T6, T7, T8>::value;
+
+ //***************************************************************************
+ /// The type used for ids.
+ //***************************************************************************
+ typedef uint8_t type_id_t;
+
+ //***************************************************************************
+ /// The id a unsupported types.
+ //***************************************************************************
+ static const type_id_t UNSUPPORTED_TYPE_ID = integral_limits<type_id_t>::max;
+
+ //***************************************************************************
+ /// Do we pass this type by value?
+ //***************************************************************************
+ template <typename T>
+ struct pass_by_value : integral_constant<bool, etl::is_fundamental<T>::value || etl::is_pointer<T>::value>
+ {
+ };
+
+ //***************************************************************************
+ /// Define the type for a parameter.
+ //***************************************************************************
+ template <typename T, bool>
+ struct type_definition;
+
+ //***************************************************************************
+ /// Pass by value.
+ //***************************************************************************
+ template <typename T>
+ struct type_definition<T, true>
+ {
+ typedef T type;
+ };
+
+ //***************************************************************************
+ /// Pass by const reference.
+ //***************************************************************************
+ template <typename T>
+ struct type_definition<T, false>
+ {
+ typedef const T& type;
+ };
+
+ //***************************************************************************
+ /// Determines the type for parameters.
+ //***************************************************************************
+ template <typename T>
+ struct parameter_type : public type_definition<T, pass_by_value<T>::value>
+ {
+ };
+
+ //***************************************************************************
+ /// Short form of no_type placeholders.
+ //***************************************************************************
+ typedef __private_variant__::no_type<2> no_type2;
+ typedef __private_variant__::no_type<3> no_type3;
+ typedef __private_variant__::no_type<4> no_type4;
+ typedef __private_variant__::no_type<5> no_type5;
+ typedef __private_variant__::no_type<6> no_type6;
+ typedef __private_variant__::no_type<7> no_type7;
+ typedef __private_variant__::no_type<8> no_type8;
+
+ //***************************************************************************
+ /// Lookup the id of type.
+ //***************************************************************************
+ template <typename T>
+ struct Type_Id_Lookup
+ {
+ static const uint8_t type_id = etl::is_same<T, T1>::value ? 0 :
+ etl::is_same<T, T2>::value ? 1 :
+ etl::is_same<T, T3>::value ? 2 :
+ etl::is_same<T, T4>::value ? 3 :
+ etl::is_same<T, T5>::value ? 4 :
+ etl::is_same<T, T6>::value ? 5 :
+ etl::is_same<T, T7>::value ? 6 :
+ etl::is_same<T, T8>::value ? 7 :
+ UNSUPPORTED_TYPE_ID;
+ };
+
+ //***************************************************************************
+ /// Lookup for the id of type.
+ //***************************************************************************
+ template <typename T>
+ struct Type_Is_Supported : public integral_constant<bool,
+ is_same<T, T1>::value ||
+ is_same<T, T2>::value ||
+ is_same<T, T3>::value ||
+ is_same<T, T4>::value ||
+ is_same<T, T5>::value ||
+ is_same<T, T6>::value ||
+ is_same<T, T7>::value ||
+ is_same<T, T8>::value>
+ {
+ };
+
+ public:
+
+ //*************************************************************************
+ //**** Reader types *******************************************************
+ //*************************************************************************
+
+ //*************************************************************************
+ /// Base reader type functor class.
+ /// Allows for typesafe access to the stored value types.
+ /// Define the reader type for 8 types.
+ //*************************************************************************
+ template <typename R1, typename R2 = no_type2, typename R3 = no_type3, typename R4 = no_type4, typename R5 = no_type5, typename R6 = no_type6, typename R7 = no_type7, typename R8 = no_type8>
+ class reader_type
+ {
+ public:
+
+ friend class variant;
+
+ virtual void read(typename parameter_type<R1>::type value) = 0;
+ virtual void read(typename parameter_type<R2>::type value) = 0;
+ virtual void read(typename parameter_type<R3>::type value) = 0;
+ virtual void read(typename parameter_type<R4>::type value) = 0;
+ virtual void read(typename parameter_type<R5>::type value) = 0;
+ virtual void read(typename parameter_type<R6>::type value) = 0;
+ virtual void read(typename parameter_type<R7>::type value) = 0;
+ virtual void read(typename parameter_type<R8>::type value) = 0;
+ };
+
+ //*************************************************************************
+ /// Define the reader type for 7 types.
+ //*************************************************************************
+ template <typename R1, typename R2, typename R3, typename R4, typename R5, typename R6, typename R7>
+ class reader_type<R1, R2, R3, R4, R5, R6, R7, no_type8>
+ {
+ public:
+
+ friend class variant;
+
+ virtual void read(typename parameter_type<R1>::type value) = 0;
+ virtual void read(typename parameter_type<R2>::type value) = 0;
+ virtual void read(typename parameter_type<R3>::type value) = 0;
+ virtual void read(typename parameter_type<R4>::type value) = 0;
+ virtual void read(typename parameter_type<R5>::type value) = 0;
+ virtual void read(typename parameter_type<R6>::type value) = 0;
+ virtual void read(typename parameter_type<R7>::type value) = 0;
+
+ private:
+
+ void read(no_type8&) {};
+ };
+
+ //*************************************************************************
+ /// Define the reader type for 6 types.
+ //*************************************************************************
+ template <typename R1, typename R2, typename R3, typename R4, typename R5, typename R6>
+ class reader_type<R1, R2, R3, R4, R5, R6, no_type7, no_type8>
+ {
+ public:
+
+ friend class variant;
+
+ virtual void read(typename parameter_type<R1>::type value) = 0;
+ virtual void read(typename parameter_type<R2>::type value) = 0;
+ virtual void read(typename parameter_type<R3>::type value) = 0;
+ virtual void read(typename parameter_type<R4>::type value) = 0;
+ virtual void read(typename parameter_type<R5>::type value) = 0;
+ virtual void read(typename parameter_type<R6>::type value) = 0;
+
+ private:
+
+ void read(no_type7&) {};
+ void read(no_type8&) {};
+ };
+
+ //*************************************************************************
+ /// Define the reader type for 5 types.
+ //*************************************************************************
+ template <typename R1, typename R2, typename R3, typename R4, typename R5>
+ class reader_type<R1, R2, R3, R4, R5, no_type6, no_type7, no_type8>
+ {
+ public:
+
+ friend class variant;
+
+ virtual void read(typename parameter_type<R1>::type value) = 0;
+ virtual void read(typename parameter_type<R2>::type value) = 0;
+ virtual void read(typename parameter_type<R3>::type value) = 0;
+ virtual void read(typename parameter_type<R4>::type value) = 0;
+ virtual void read(typename parameter_type<R5>::type value) = 0;
+
+ private:
+
+ void read(no_type6&) {};
+ void read(no_type7&) {};
+ void read(no_type8&) {};
+ };
+
+ //*************************************************************************
+ /// Define the reader type for 4 types.
+ //*************************************************************************
+ template <typename R1, typename R2, typename R3, typename R4>
+ class reader_type<R1, R2, R3, R4, no_type5, no_type6, no_type7, no_type8>
+ {
+ public:
+
+ friend class variant;
+
+ virtual void read(typename parameter_type<R1>::type value) = 0;
+ virtual void read(typename parameter_type<R2>::type value) = 0;
+ virtual void read(typename parameter_type<R3>::type value) = 0;
+ virtual void read(typename parameter_type<R4>::type value) = 0;
+
+ private:
+
+ void read(no_type5&) {};
+ void read(no_type6&) {};
+ void read(no_type7&) {};
+ void read(no_type8&) {};
+ };
+
+ //*************************************************************************
+ /// Define the reader type for 3 types.
+ //*************************************************************************
+ template <typename R1, typename R2, typename R3>
+ class reader_type<R1, R2, R3, no_type4, no_type5, no_type6, no_type7, no_type8>
+ {
+ public:
+
+ friend class variant;
+
+ virtual void read(typename parameter_type<R1>::type value) = 0;
+ virtual void read(typename parameter_type<R2>::type value) = 0;
+ virtual void read(typename parameter_type<R3>::type value) = 0;
+
+ private:
+
+ void read(no_type4&) {};
+ void read(no_type5&) {};
+ void read(no_type6&) {};
+ void read(no_type7&) {};
+ void read(no_type8&) {};
+ };
+
+ //*************************************************************************
+ /// Define the reader type for 2 types.
+ //*************************************************************************
+ template <typename R1, typename R2>
+ class reader_type<R1, R2, no_type3, no_type4, no_type5, no_type6, no_type7, no_type8>
+ {
+ public:
+
+ friend class variant;
+
+ virtual void read(typename parameter_type<R1>::type value) = 0;
+ virtual void read(typename parameter_type<R2>::type value) = 0;
+
+ private:
+
+ void read(no_type3&) {};
+ void read(no_type4&) {};
+ void read(no_type5&) {};
+ void read(no_type6&) {};
+ void read(no_type7&) {};
+ void read(no_type8&) {};
+ };
+
+ //*************************************************************************
+ /// Define the reader type for 1 type.
+ //*************************************************************************
+ template <typename R1>
+ class reader_type<R1, no_type2, no_type3, no_type4, no_type5, no_type6, no_type7, no_type8>
+ {
+ public:
+
+ friend class variant;
+
+ virtual void read(typename parameter_type<R1>::type value) = 0;
+
+ private:
+
+ void read(no_type2&) {};
+ void read(no_type3&) {};
+ void read(no_type4&) {};
+ void read(no_type5&) {};
+ void read(no_type6&) {};
+ void read(no_type7&) {};
+ void read(no_type8&) {};
+ };
+
+ //*************************************************************************
+ //**** Up-cast functors ***************************************************
+ //*************************************************************************
+
+ //*************************************************************************
+ /// Base upcast_functor for eight types.
+ //*************************************************************************
+ template <typename TBase, typename U1, typename U2 = no_type2, typename U3 = no_type3, typename U4 = no_type4, typename U5 = no_type5, typename U6 = no_type6, typename U7 = no_type7, typename U8 = no_type8>
+ class upcast_functor
+ {
+ public:
+
+ TBase& operator()(uint8_t* p_data, uint8_t typeId)
+ {
+ switch (typeId)
+ {
+ case 0: return reinterpret_cast<U1&>(*p_data);
+ case 1: return reinterpret_cast<U2&>(*p_data);
+ case 2: return reinterpret_cast<U3&>(*p_data);
+ case 3: return reinterpret_cast<U4&>(*p_data);
+ case 4: return reinterpret_cast<U5&>(*p_data);
+ case 5: return reinterpret_cast<U6&>(*p_data);
+ case 6: return reinterpret_cast<U7&>(*p_data);
+ case 7: return reinterpret_cast<U8&>(*p_data);
+ default: return reinterpret_cast<TBase&>(*reinterpret_cast<TBase*>(0));
+ }
+ }
+
+ const TBase& operator()(uint8_t* p_data, uint8_t typeId) const
+ {
+ switch (typeId)
+ {
+ case 0: return reinterpret_cast<const U1&>(*p_data);
+ case 1: return reinterpret_cast<const U2&>(*p_data);
+ case 2: return reinterpret_cast<const U3&>(*p_data);
+ case 3: return reinterpret_cast<const U4&>(*p_data);
+ case 4: return reinterpret_cast<const U5&>(*p_data);
+ case 5: return reinterpret_cast<const U6&>(*p_data);
+ case 6: return reinterpret_cast<const U7&>(*p_data);
+ case 7: return reinterpret_cast<const U8&>(*p_data);
+ default: return reinterpret_cast<const TBase&>(*reinterpret_cast<const TBase*>(0));
+ }
+ }
+ };
+
+ //*************************************************************************
+ /// Upcast_functor for seven types.
+ //*************************************************************************
+ template <typename TBase, typename U1, typename U2, typename U3, typename U4, typename U5, typename U6, typename U7>
+ class upcast_functor<TBase, U1, U2, U3, U4, U5, U6, U7, no_type8>
+ {
+ public:
+
+ TBase& operator()(uint8_t* p_data, uint8_t typeId)
+ {
+ switch (typeId)
+ {
+ case 0: return reinterpret_cast<U1&>(*p_data);
+ case 1: return reinterpret_cast<U2&>(*p_data);
+ case 2: return reinterpret_cast<U3&>(*p_data);
+ case 3: return reinterpret_cast<U4&>(*p_data);
+ case 4: return reinterpret_cast<U5&>(*p_data);
+ case 5: return reinterpret_cast<U6&>(*p_data);
+ case 6: return reinterpret_cast<U7&>(*p_data);
+ default: return reinterpret_cast<TBase&>(*reinterpret_cast<TBase*>(0));
+ }
+ }
+
+ const TBase& operator()(uint8_t* p_data, uint8_t typeId) const
+ {
+ switch (typeId)
+ {
+ case 0: return reinterpret_cast<const U1&>(*p_data);
+ case 1: return reinterpret_cast<const U2&>(*p_data);
+ case 2: return reinterpret_cast<const U3&>(*p_data);
+ case 3: return reinterpret_cast<const U4&>(*p_data);
+ case 4: return reinterpret_cast<const U5&>(*p_data);
+ case 5: return reinterpret_cast<const U6&>(*p_data);
+ case 6: return reinterpret_cast<const U7&>(*p_data);
+ default: return reinterpret_cast<const TBase&>(*reinterpret_cast<const TBase*>(0));
+ }
+ }
+ };
+
+ //*************************************************************************
+ /// Upcast_functor for six types.
+ //*************************************************************************
+ template <typename TBase, typename U1, typename U2, typename U3, typename U4, typename U5, typename U6>
+ class upcast_functor<TBase, U1, U2, U3, U4, U5, U6, no_type7, no_type8>
+ {
+ public:
+
+ TBase& operator()(uint8_t* p_data, uint8_t typeId)
+ {
+ switch (typeId)
+ {
+ case 0: return reinterpret_cast<U1&>(*p_data);
+ case 1: return reinterpret_cast<U2&>(*p_data);
+ case 2: return reinterpret_cast<U3&>(*p_data);
+ case 3: return reinterpret_cast<U4&>(*p_data);
+ case 4: return reinterpret_cast<U5&>(*p_data);
+ case 5: return reinterpret_cast<U6&>(*p_data);
+ default: return reinterpret_cast<TBase&>(*reinterpret_cast<TBase*>(0));
+ }
+ }
+
+ const TBase& operator()(uint8_t* p_data, uint8_t typeId) const
+ {
+ switch (typeId)
+ {
+ case 0: return reinterpret_cast<const U1&>(*p_data);
+ case 1: return reinterpret_cast<const U2&>(*p_data);
+ case 2: return reinterpret_cast<const U3&>(*p_data);
+ case 3: return reinterpret_cast<const U4&>(*p_data);
+ case 4: return reinterpret_cast<const U5&>(*p_data);
+ case 5: return reinterpret_cast<const U6&>(*p_data);
+ default: return reinterpret_cast<const TBase&>(*reinterpret_cast<const TBase*>(0));
+ }
+ }
+ };
+
+ //*************************************************************************
+ /// Upcast_functor for five types.
+ //*************************************************************************
+ template <typename TBase, typename U1, typename U2, typename U3, typename U4, typename U5>
+ class upcast_functor<TBase, U1, U2, U3, U4, U5, no_type6, no_type7, no_type8>
+ {
+ public:
+
+ TBase& operator()(uint8_t* p_data, uint8_t typeId)
+ {
+ switch (typeId)
+ {
+ case 0: return reinterpret_cast<U1&>(*p_data);
+ case 1: return reinterpret_cast<U2&>(*p_data);
+ case 2: return reinterpret_cast<U3&>(*p_data);
+ case 3: return reinterpret_cast<U4&>(*p_data);
+ case 4: return reinterpret_cast<U5&>(*p_data);
+ default: return reinterpret_cast<TBase&>(*reinterpret_cast<TBase*>(0));
+ }
+ }
+
+ const TBase& operator()(uint8_t* p_data, uint8_t typeId) const
+ {
+ switch (typeId)
+ {
+ case 0: return reinterpret_cast<const U1&>(*p_data);
+ case 1: return reinterpret_cast<const U2&>(*p_data);
+ case 2: return reinterpret_cast<const U3&>(*p_data);
+ case 3: return reinterpret_cast<const U4&>(*p_data);
+ case 4: return reinterpret_cast<const U5&>(*p_data);
+ default: return reinterpret_cast<const TBase&>(*reinterpret_cast<const TBase*>(0));
+ }
+ }
+ };
+
+ //*************************************************************************
+ /// Upcast_functor for four types.
+ //*************************************************************************
+ template <typename TBase, typename U1, typename U2, typename U3, typename U4>
+ class upcast_functor<TBase, U1, U2, U3, U4, no_type5, no_type6, no_type7, no_type8>
+ {
+ public:
+
+ TBase& operator()(uint8_t* p_data, uint8_t typeId)
+ {
+ switch (typeId)
+ {
+ case 0: return reinterpret_cast<U1&>(*p_data);
+ case 1: return reinterpret_cast<U2&>(*p_data);
+ case 2: return reinterpret_cast<U3&>(*p_data);
+ case 3: return reinterpret_cast<U4&>(*p_data);
+ default: return reinterpret_cast<TBase&>(*reinterpret_cast<TBase*>(0));
+ }
+ }
+
+ const TBase& operator()(uint8_t* p_data, uint8_t typeId) const
+ {
+ switch (typeId)
+ {
+ case 0: return reinterpret_cast<const U1&>(*p_data);
+ case 1: return reinterpret_cast<const U2&>(*p_data);
+ case 2: return reinterpret_cast<const U3&>(*p_data);
+ case 3: return reinterpret_cast<const U4&>(*p_data);
+ default: return reinterpret_cast<const TBase&>(*reinterpret_cast<const TBase*>(0));
+ }
+ }
+ };
+
+ //*************************************************************************
+ /// Upcast_functor for three types.
+ //*************************************************************************
+ template <typename TBase, typename U1, typename U2, typename U3>
+ class upcast_functor<TBase, U1, U2, U3, no_type4, no_type5, no_type6, no_type7, no_type8>
+ {
+ public:
+
+ TBase& operator()(uint8_t* p_data, uint8_t typeId)
+ {
+ switch (typeId)
+ {
+ case 0: return reinterpret_cast<U1&>(*p_data);
+ case 1: return reinterpret_cast<U2&>(*p_data);
+ case 2: return reinterpret_cast<U3&>(*p_data);
+ default: return reinterpret_cast<TBase&>(*reinterpret_cast<TBase*>(0));
+ }
+ }
+
+ const TBase& operator()(uint8_t* p_data, uint8_t typeId) const
+ {
+ switch (typeId)
+ {
+ case 0: return reinterpret_cast<const U1&>(*p_data);
+ case 1: return reinterpret_cast<const U2&>(*p_data);
+ case 2: return reinterpret_cast<const U3&>(*p_data);
+ default: return reinterpret_cast<const TBase&>(*reinterpret_cast<const TBase*>(0));
+ }
+ }
+ };
+
+ //*************************************************************************
+ /// Upcast_functor for two types.
+ //*************************************************************************
+ template <typename TBase, typename U1, typename U2>
+ class upcast_functor<TBase, U1, U2, no_type3, no_type4, no_type5, no_type6, no_type7, no_type8>
+ {
+ public:
+
+ TBase& operator()(uint8_t* p_data, uint8_t typeId)
+ {
+ switch (typeId)
+ {
+ case 0: return reinterpret_cast<U1&>(*p_data);
+ case 1: return reinterpret_cast<U2&>(*p_data);
+ default: return reinterpret_cast<TBase&>(*reinterpret_cast<TBase*>(0));
+ }
+ }
+
+ const TBase& operator()(uint8_t* p_data, uint8_t typeId) const
+ {
+ switch (typeId)
+ {
+ case 0: return reinterpret_cast<const U1&>(*p_data);
+ case 1: return reinterpret_cast<const U2&>(*p_data);
+ default: return reinterpret_cast<const TBase&>(*reinterpret_cast<const TBase*>(0));
+ }
+ }
+ };
+
+ //*************************************************************************
+ /// Upcast_functor for one type.
+ //*************************************************************************
+ template <typename TBase, typename U1>
+ class upcast_functor<TBase, U1, no_type2, no_type3, no_type4, no_type5, no_type6, no_type7, no_type8>
+ {
+ public:
+
+ TBase& operator()(uint8_t* p_data, uint8_t typeId)
+ {
+ return reinterpret_cast<U1&>(*p_data);
+ }
+
+ const TBase& operator()(uint8_t* p_data, uint8_t typeId) const
+ {
+ return reinterpret_cast<const U1&>(*p_data);
+ }
+ };
+
+ //***************************************************************************
+ /// The base type for derived readers.
+ //***************************************************************************
+ typedef reader_type<T1, T2, T3, T4, T5, T6, T7, T8> reader;
+
+ //***************************************************************************
+ /// Default constructor.
+ /// Sets the state of the instance to containing no valid data.
+ //***************************************************************************
+ variant()
+ : type_id(UNSUPPORTED_TYPE_ID)
+ {
+ }
+
+ //***************************************************************************
+ /// Constructor that catches any types that are not supported.
+ /// Forces a STATIC_ASSERT.
+ //***************************************************************************
+ template <typename T>
+ variant(const T& value)
+ {
+ STATIC_ASSERT(Type_Is_Supported<T>::value, "Unsupported type");
+
+ new(static_cast<T*>(data)) T(value);
+ type_id = Type_Id_Lookup<T>::type_id;
+ }
+
+ //***************************************************************************
+ /// Copy constructor.
+ ///\param other The other variant object to copy.
+ //***************************************************************************
+ variant(const variant& other)
+ : data(other.data),
+ type_id(other.type_id)
+ {
+ }
+
+ //***************************************************************************
+ /// Assignment operator for T1 type.
+ ///\param value The value to assign.
+ //***************************************************************************
+ template <typename T>
+ variant& operator =(const T& value)
+ {
+ STATIC_ASSERT(Type_Is_Supported<T>::value, "Unsupported type");
+
+ // Assigning the same type as last time?
+ if (type_id == Type_Id_Lookup<T>::type_id)
+ {
+ // Do a simple copy.
+ *static_cast<T*>(data) = value;
+ }
+ else
+ {
+ // We must destruct the old type, as the new one is different.
+ destruct_current();
+ new(static_cast<T*>(data)) T(value);
+ type_id = Type_Id_Lookup<T>::type_id;
+ }
+
+ return *this;
+ }
+
+ //***************************************************************************
+ /// Checks if the type is the same as the current stored type.
+ /// For variants with the same type declarations.
+ ///\return <b>true</b> if the types are the same, otherwise <b>false</b>.
+ //***************************************************************************
+ bool is_same_type(const variant& other) const
+ {
+ return type_id == other.type_id;
+ }
+
+ //***************************************************************************
+ /// Checks if the type is the same as the current stored type.
+ /// For variants with differing declarations.
+ ///\return <b>true</b> if the types are the same, otherwise <b>false</b>.
+ //***************************************************************************
+ template <typename U1, typename U2, typename U3, typename U4, typename U5, typename U6, typename U7, typename U8>
+ bool is_same_type(const variant<U1, U2, U3, U4, U5, U6, U7, U8>& other) const
+ {
+ bool is_same_type = false;
+
+ switch (other.type_id)
+ {
+ case 0: is_same_type = type_id == Type_Id_Lookup<U1>::type_id; break;
+ case 1: is_same_type = type_id == Type_Id_Lookup<U2>::type_id; break;
+ case 2: is_same_type = type_id == Type_Id_Lookup<U3>::type_id; break;
+ case 3: is_same_type = type_id == Type_Id_Lookup<U4>::type_id; break;
+ case 4: is_same_type = type_id == Type_Id_Lookup<U5>::type_id; break;
+ case 5: is_same_type = type_id == Type_Id_Lookup<U6>::type_id; break;
+ case 6: is_same_type = type_id == Type_Id_Lookup<U7>::type_id; break;
+ case 7: is_same_type = type_id == Type_Id_Lookup<U8>::type_id; break;
+ default: break;
+ }
+
+ return is_same_type;
+ }
+
+ //***************************************************************************
+ /// Calls the supplied reader instance.
+ /// The 'read' function appropriate to the current type is called with the stored value.
+ //***************************************************************************
+ void call(reader& reader)
+ {
+ switch (type_id)
+ {
+ case 0: reader.read(static_cast<T1&>(data)); break;
+ case 1: reader.read(static_cast<T2&>(data)); break;
+ case 2: reader.read(static_cast<T3&>(data)); break;
+ case 3: reader.read(static_cast<T4&>(data)); break;
+ case 4: reader.read(static_cast<T5&>(data)); break;
+ case 5: reader.read(static_cast<T6&>(data)); break;
+ case 6: reader.read(static_cast<T7&>(data)); break;
+ case 7: reader.read(static_cast<T8&>(data)); break;
+ default: break;
+ }
+ }
+
+ //***************************************************************************
+ /// Checks whether a valid value is currently stored.
+ ///\return <b>true</b> if the value is valid, otherwise <b>false</b>.
+ //***************************************************************************
+ bool is_valid() const
+ {
+ return type_id != UNSUPPORTED_TYPE_ID;
+ }
+
+ //***************************************************************************
+ /// Checks to see if the type currently stored is the same as that specified in the template parameter.
+ ///\return <b>true</b> if it is the specified type, otherwise <b>false</b>.
+ //***************************************************************************
+ template <typename T>
+ bool is_type() const
+ {
+ return type_id == Type_Id_Lookup<T>::type_id;
+ }
+
+ //***************************************************************************
+ /// Clears the value to 'no valid stored value'.
+ //***************************************************************************
+ void clear()
+ {
+ type_id = UNSUPPORTED_TYPE_ID;
+ }
+
+ //***************************************************************************
+ /// Gets the value stored as the specified template type.
+ /// Throws a variant_incorrect_type_exception if the actual type is not that specified.
+ ///\return A reference to the value.
+ //***************************************************************************
+ template <typename T>
+ T& get()
+ {
+ STATIC_ASSERT(Type_Is_Supported<T>::value, "Unsupported type");
+ ETL_ASSERT(is_type<T>(), ETL_ERROR(variant_incorrect_type_exception));
+
+ return static_cast<T&>(data);
+ }
+
+ //***************************************************************************
+ /// Gets the value stored as the specified template type.
+ /// Throws a variant_incorrect_type_exception if the actual type is not that specified.
+ ///\return A const reference to the value.
+ //***************************************************************************
+ template <typename T>
+ const T& get() const
+ {
+ STATIC_ASSERT(Type_Is_Supported<T>::value, "Unsupported type");
+ ETL_ASSERT(is_type<T>(), ETL_ERROR(variant_incorrect_type_exception));
+
+ return static_cast<const T&>(data);
+ }
+
+ //***************************************************************************
+ /// Gets the value stored as the specified template type.
+ ///\return A reference to the value.
+ //***************************************************************************
+ template <typename TBase>
+ TBase& upcast()
+ {
+ return upcast_functor<TBase, T1, T2, T3, T4, T5, T6, T7, T8>()(data, type_id);
+ }
+
+ //***************************************************************************
+ /// Gets the value stored as the specified template type.
+ ///\return A const reference to the value.
+ //***************************************************************************
+ template <typename TBase>
+ const TBase& upcast() const
+ {
+ return upcast_functor<TBase, T1, T2, T3, T4, T5, T6, T7, T8>()(data, type_id);
+ }
+
+ //***************************************************************************
+ /// Conversion operators for each type.
+ //***************************************************************************
+ operator T1&() { return get<T1>(); }
+ operator T2&() { return get<T2>(); }
+ operator T3&() { return get<T3>(); }
+ operator T4&() { return get<T4>(); }
+ operator T5&() { return get<T5>(); }
+ operator T6&() { return get<T6>(); }
+ operator T7&() { return get<T7>(); }
+ operator T8&() { return get<T8>(); }
+
+ //***************************************************************************
+ /// Checks if the template type is supported by the implementation of variant..
+ ///\return <b>true</b> if the type is supported, otherwise <b>false</b>.
+ //***************************************************************************
+ template <typename T>
+ static bool is_supported_type()
+ {
+ return Type_Is_Supported<T>::value;
+ }
+
+ private:
+
+ //***************************************************************************
+ /// Destruct the current occupant of the variant.
+ //***************************************************************************
+ void destruct_current()
+ {
+ switch (type_id)
+ {
+ case 0: { static_cast<T1*>(data)->~T1(); break; }
+ case 1: { static_cast<T2*>(data)->~T2(); break; }
+ case 2: { static_cast<T3*>(data)->~T3(); break; }
+ case 3: { static_cast<T4*>(data)->~T4(); break; }
+ case 4: { static_cast<T5*>(data)->~T5(); break; }
+ case 5: { static_cast<T6*>(data)->~T6(); break; }
+ case 6: { static_cast<T7*>(data)->~T7(); break; }
+ case 7: { static_cast<T8*>(data)->~T8(); break; }
+ default: { break; }
+ }
+ }
+
+ //***************************************************************************
+ /// The internal storage.
+ /// Aligned on a suitable boundary, which should be good for all types.
+ //***************************************************************************
+ typename etl::aligned_storage<sizeof(largest_t), etl::largest_alignment<T1, T2, T3, T4, T5, T6, T7, T8>::value>::type data;
+
+ //***************************************************************************
+ /// The id of the current stored type.
+ //***************************************************************************
+ type_id_t type_id;
+ };
+}
+
+#undef ETL_FILE
+
+#endif
diff --git a/lib/etl/vector.h b/lib/etl/vector.h
new file mode 100644
index 0000000..86a4998
--- /dev/null
+++ b/lib/etl/vector.h
@@ -0,0 +1,223 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_VECTOR__
+#define __ETL_VECTOR__
+
+#include <stddef.h>
+#include <stdint.h>
+#include <iterator>
+
+#include "ivector.h"
+#include "container.h"
+#include "alignment.h"
+#include "array.h"
+
+//*****************************************************************************
+///\defgroup vector vector
+/// A vector with the capacity defined at compile time.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+ //***************************************************************************
+ /// A vector implementation that uses a fixed size buffer.
+ ///\tparam T The element type.
+ ///\tparam MAX_SIZE_ The maximum number of elements that can be stored.
+ ///\ingroup vector
+ //***************************************************************************
+ template <typename T, const size_t MAX_SIZE_>
+ class vector : public ivector<T>
+ {
+ public:
+
+ static const size_t MAX_SIZE = MAX_SIZE_;
+
+ //*************************************************************************
+ /// Constructor.
+ //*************************************************************************
+ vector()
+ : ivector<T>(reinterpret_cast<T*>(&buffer), MAX_SIZE)
+ {
+ ivector<T>::initialise();
+ }
+
+ //*************************************************************************
+ /// Constructor, with size.
+ ///\param initial_size The initial size of the vector.
+ //*************************************************************************
+ explicit vector(size_t initial_size)
+ : ivector<T>(reinterpret_cast<T*>(&buffer), MAX_SIZE)
+ {
+ ivector<T>::initialise();
+ ivector<T>::resize(initial_size);
+ }
+
+ //*************************************************************************
+ /// Constructor, from initial size and value.
+ ///\param initial_size The initial size of the vector.
+ ///\param value The value to fill the vector with.
+ //*************************************************************************
+ vector(size_t initial_size, typename ivector<T>::parameter_t value)
+ : ivector<T>(reinterpret_cast<T*>(&buffer), MAX_SIZE)
+ {
+ ivector<T>::initialise();
+ ivector<T>::resize(initial_size, value);
+ }
+
+ //*************************************************************************
+ /// Constructor, from an iterator range.
+ ///\tparam TIterator The iterator type.
+ ///\param first The iterator to the first element.
+ ///\param last The iterator to the last element + 1.
+ //*************************************************************************
+ template <typename TIterator>
+ vector(TIterator first, TIterator last)
+ : ivector<T>(reinterpret_cast<T*>(&buffer), MAX_SIZE)
+ {
+ ivector<T>::assign(first, last);
+ }
+
+ //*************************************************************************
+ /// Copy constructor.
+ //*************************************************************************
+ vector(const vector& other)
+ : ivector<T>(reinterpret_cast<T*>(&buffer), MAX_SIZE)
+ {
+ ivector<T>::assign(other.begin(), other.end());
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ vector& operator = (const vector& rhs)
+ {
+ if (&rhs != this)
+ {
+ ivector<T>::assign(rhs.cbegin(), rhs.cend());
+ }
+
+ return *this;
+ }
+
+ private:
+
+ typename etl::aligned_storage<sizeof(T) * MAX_SIZE, etl::alignment_of<T>::value>::type buffer;
+ };
+
+
+ //***************************************************************************
+ /// A vector implementation that uses a fixed size buffer.
+ ///\tparam T The element type.
+ ///\tparam MAX_SIZE_ The maximum number of elements that can be stored.
+ ///\ingroup vector
+ //***************************************************************************
+ template <typename T, const size_t MAX_SIZE_>
+ class vector<T*, MAX_SIZE_> : public ivector<T*>
+ {
+ public:
+
+ static const size_t MAX_SIZE = MAX_SIZE_;
+
+ //*************************************************************************
+ /// Constructor.
+ //*************************************************************************
+ vector()
+ : ivector<T*>(reinterpret_cast<T**>(&buffer), MAX_SIZE)
+ {
+ ivector<T*>::initialise();
+ }
+
+ //*************************************************************************
+ /// Constructor, with size.
+ ///\param initial_size The initial size of the vector.
+ //*************************************************************************
+ explicit vector(size_t initial_size)
+ : ivector<T*>(reinterpret_cast<T**>(&buffer), MAX_SIZE)
+ {
+ ivector<T*>::initialise();
+ ivector<T*>::resize(initial_size);
+ }
+
+ //*************************************************************************
+ /// Constructor, from initial size and value.
+ ///\param initial_size The initial size of the vector.
+ ///\param value The value to fill the vector with.
+ //*************************************************************************
+ vector(size_t initial_size, typename ivector<T*>::parameter_t value)
+ : ivector<T*>(reinterpret_cast<T**>(&buffer), MAX_SIZE)
+ {
+ ivector<T*>::initialise();
+ ivector<T*>::resize(initial_size, value);
+ }
+
+ //*************************************************************************
+ /// Constructor, from an iterator range.
+ ///\tparam TIterator The iterator type.
+ ///\param first The iterator to the first element.
+ ///\param last The iterator to the last element + 1.
+ //*************************************************************************
+ template <typename TIterator>
+ vector(TIterator first, TIterator last)
+ : ivector<T*>(reinterpret_cast<T**>(&buffer), MAX_SIZE)
+ {
+ ivector<T*>::assign(first, last);
+ }
+
+ //*************************************************************************
+ /// Copy constructor.
+ //*************************************************************************
+ vector(const vector& other)
+ : ivector<T*>(reinterpret_cast<T**>(&buffer), MAX_SIZE)
+ {
+ ivector<T*>::assign(other.begin(), other.end());
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ vector& operator = (const vector& rhs)
+ {
+ if (&rhs != this)
+ {
+ ivector<T*>::assign(rhs.cbegin(), rhs.cend());
+ }
+
+ return *this;
+ }
+
+ private:
+
+ typename etl::aligned_storage<sizeof(T*) * MAX_SIZE, etl::alignment_of<T*>::value>::type buffer;
+ };
+}
+
+#endif
diff --git a/lib/etl/visitor.h b/lib/etl/visitor.h
new file mode 100644
index 0000000..c7af354
--- /dev/null
+++ b/lib/etl/visitor.h
@@ -0,0 +1,462 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_VISITOR__
+#define __ETL_VISITOR__
+
+//*****************************************************************************
+///\defgroup visitor visitor
+/// A set of template classes for easy implementation of the visitor pattern.<br>
+/// The visitor design pattern is a way of separating an algorithm from an object
+/// structure on which it operates. A practical result of this separation is the
+/// ability to add new operations to existing object structures without modifying
+/// those structures. It is one way to easily follow the open/closed principle.
+/// In essence, the visitor allows one to add new virtual functions to a family
+/// of classes without modifying the classes themselves; instead, one creates a
+/// visitor class that implements all of the appropriate specialisations of the
+/// virtual function. The visitor takes the instance as input, and implements
+/// the goal through double dispatch.<br>
+/// \ingroup patterns
+//*****************************************************************************
+
+namespace etl
+{
+ //*****************************************************************
+ /// The visitable base class for four visitor types.
+ /// Derive visitable classes from this.
+ ///\ingroup visitor
+ //*****************************************************************
+ template <typename T1, typename T2 = void, typename T3 = void, typename T4 = void>
+ class visitable
+ {
+ public:
+
+ virtual void accept(T1&) = 0;
+ virtual void accept(T2&) = 0;
+ virtual void accept(T3&) = 0;
+ virtual void accept(T4&) = 0;
+ };
+
+ //*****************************************************************
+ /// The visitable base class for three visitor types.
+ /// Derive visitable classes from this.
+ ///\ingroup visitor
+ //*****************************************************************
+ template <typename T1, typename T2, typename T3>
+ class visitable<T1, T2, T3>
+ {
+ public:
+
+ virtual void accept(T1&) = 0;
+ virtual void accept(T2&) = 0;
+ virtual void accept(T3&) = 0;
+ };
+
+ //*****************************************************************
+ /// The visitable base class for two visitor types.
+ /// Derive visitable classes from this.
+ ///\ingroup visitor
+ //*****************************************************************
+ template <typename T1, typename T2>
+ class visitable<T1, T2>
+ {
+ public:
+
+ virtual void accept(T1&) = 0;
+ virtual void accept(T2&) = 0;
+ };
+
+ //*****************************************************************
+ /// The visitable base class for one visitor type.
+ /// Derive visitable classes from this.
+ ///\ingroup visitor
+ //*****************************************************************
+ template <typename T1>
+ class visitable<T1>
+ {
+ public:
+
+ virtual void accept(T1&) = 0;
+ };
+
+ //*****************************************************************
+ /// The visitor base class for sixteen types.
+ /// Derive visitors from this.
+ ///\ingroup visitor
+ //*****************************************************************
+ template <typename T1, typename T2 = void, typename T3 = void, typename T4 = void,
+ typename T5 = void, typename T6 = void, typename T7 = void, typename T8 = void,
+ typename T9 = void, typename T10 = void, typename T11 = void, typename T12 = void,
+ typename T13 = void, typename T14 = void, typename T15 = void, typename T16 = void>
+ class visitor
+ {
+ public:
+
+ virtual void visit(T1&) = 0;
+ virtual void visit(T2&) = 0;
+ virtual void visit(T3&) = 0;
+ virtual void visit(T4&) = 0;
+ virtual void visit(T5&) = 0;
+ virtual void visit(T6&) = 0;
+ virtual void visit(T7&) = 0;
+ virtual void visit(T8&) = 0;
+ virtual void visit(T9&) = 0;
+ virtual void visit(T10&) = 0;
+ virtual void visit(T11&) = 0;
+ virtual void visit(T12&) = 0;
+ virtual void visit(T13&) = 0;
+ virtual void visit(T14&) = 0;
+ virtual void visit(T15&) = 0;
+ virtual void visit(T16&) = 0;
+ };
+
+ //*****************************************************************
+ /// The visitor base class for fifteen types.
+ /// Derive visitors from this.
+ ///\ingroup visitor
+ //*****************************************************************
+ template <typename T1, typename T2, typename T3, typename T4,
+ typename T5, typename T6, typename T7, typename T8,
+ typename T9, typename T10, typename T11, typename T12,
+ typename T13, typename T14, typename T15>
+ class visitor<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>
+ {
+ public:
+
+ virtual void visit(T1&) = 0;
+ virtual void visit(T2&) = 0;
+ virtual void visit(T3&) = 0;
+ virtual void visit(T4&) = 0;
+ virtual void visit(T5&) = 0;
+ virtual void visit(T6&) = 0;
+ virtual void visit(T7&) = 0;
+ virtual void visit(T8&) = 0;
+ virtual void visit(T9&) = 0;
+ virtual void visit(T10&) = 0;
+ virtual void visit(T11&) = 0;
+ virtual void visit(T12&) = 0;
+ virtual void visit(T13&) = 0;
+ virtual void visit(T14&) = 0;
+ virtual void visit(T15&) = 0;
+ };
+
+ //*****************************************************************
+ /// The visitor base class for fourteen types.
+ /// Derive visitors from this.
+ ///\ingroup visitor
+ //*****************************************************************
+ template <typename T1, typename T2, typename T3, typename T4,
+ typename T5, typename T6, typename T7, typename T8,
+ typename T9, typename T10, typename T11, typename T12,
+ typename T13, typename T14>
+ class visitor<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>
+ {
+ public:
+
+ virtual void visit(T1&) = 0;
+ virtual void visit(T2&) = 0;
+ virtual void visit(T3&) = 0;
+ virtual void visit(T4&) = 0;
+ virtual void visit(T5&) = 0;
+ virtual void visit(T6&) = 0;
+ virtual void visit(T7&) = 0;
+ virtual void visit(T8&) = 0;
+ virtual void visit(T9&) = 0;
+ virtual void visit(T10&) = 0;
+ virtual void visit(T11&) = 0;
+ virtual void visit(T12&) = 0;
+ virtual void visit(T13&) = 0;
+ virtual void visit(T14&) = 0;
+ };
+
+ //*****************************************************************
+ /// The visitor base class for thirteen types.
+ /// Derive visitors from this.
+ ///\ingroup visitor
+ //*****************************************************************
+ template <typename T1, typename T2, typename T3, typename T4,
+ typename T5, typename T6, typename T7, typename T8,
+ typename T9, typename T10, typename T11, typename T12,
+ typename T13>
+ class visitor<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>
+ {
+ public:
+
+ virtual void visit(T1&) = 0;
+ virtual void visit(T2&) = 0;
+ virtual void visit(T3&) = 0;
+ virtual void visit(T4&) = 0;
+ virtual void visit(T5&) = 0;
+ virtual void visit(T6&) = 0;
+ virtual void visit(T7&) = 0;
+ virtual void visit(T8&) = 0;
+ virtual void visit(T9&) = 0;
+ virtual void visit(T10&) = 0;
+ virtual void visit(T11&) = 0;
+ virtual void visit(T12&) = 0;
+ virtual void visit(T13&) = 0;
+ };
+
+ //*****************************************************************
+ /// The visitor base class for twelve types.
+ /// Derive visitors from this.
+ ///\ingroup visitor
+ //*****************************************************************
+ template <typename T1, typename T2, typename T3, typename T4,
+ typename T5, typename T6, typename T7, typename T8,
+ typename T9, typename T10, typename T11, typename T12>
+ class visitor<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>
+ {
+ public:
+
+ virtual void visit(T1&) = 0;
+ virtual void visit(T2&) = 0;
+ virtual void visit(T3&) = 0;
+ virtual void visit(T4&) = 0;
+ virtual void visit(T5&) = 0;
+ virtual void visit(T6&) = 0;
+ virtual void visit(T7&) = 0;
+ virtual void visit(T8&) = 0;
+ virtual void visit(T9&) = 0;
+ virtual void visit(T10&) = 0;
+ virtual void visit(T11&) = 0;
+ virtual void visit(T12&) = 0;
+ };
+
+ //*****************************************************************
+ /// The visitor base class for eleven types.
+ /// Derive visitors from this.
+ ///\ingroup visitor
+ //*****************************************************************
+ template <typename T1, typename T2, typename T3, typename T4,
+ typename T5, typename T6, typename T7, typename T8,
+ typename T9, typename T10, typename T11>
+ class visitor<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>
+ {
+ public:
+
+ virtual void visit(T1&) = 0;
+ virtual void visit(T2&) = 0;
+ virtual void visit(T3&) = 0;
+ virtual void visit(T4&) = 0;
+ virtual void visit(T5&) = 0;
+ virtual void visit(T6&) = 0;
+ virtual void visit(T7&) = 0;
+ virtual void visit(T8&) = 0;
+ virtual void visit(T9&) = 0;
+ virtual void visit(T10&) = 0;
+ virtual void visit(T11&) = 0;
+ };
+
+ //*****************************************************************
+ /// The visitor base class for ten types.
+ /// Derive visitors from this.
+ ///\ingroup visitor
+ //*****************************************************************
+ template <typename T1, typename T2, typename T3, typename T4,
+ typename T5, typename T6, typename T7, typename T8,
+ typename T9, typename T10>
+ class visitor<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>
+ {
+ public:
+
+ virtual void visit(T1&) = 0;
+ virtual void visit(T2&) = 0;
+ virtual void visit(T3&) = 0;
+ virtual void visit(T4&) = 0;
+ virtual void visit(T5&) = 0;
+ virtual void visit(T6&) = 0;
+ virtual void visit(T7&) = 0;
+ virtual void visit(T8&) = 0;
+ virtual void visit(T9&) = 0;
+ virtual void visit(T10&) = 0;
+ };
+
+ //*****************************************************************
+ /// The visitor base class for nine types.
+ /// Derive visitors from this.
+ ///\ingroup visitor
+ //*****************************************************************
+ template <typename T1, typename T2, typename T3, typename T4,
+ typename T5, typename T6, typename T7, typename T8,
+ typename T9>
+ class visitor<T1, T2, T3, T4, T5, T6, T7, T8, T9>
+ {
+ public:
+
+ virtual void visit(T1&) = 0;
+ virtual void visit(T2&) = 0;
+ virtual void visit(T3&) = 0;
+ virtual void visit(T4&) = 0;
+ virtual void visit(T5&) = 0;
+ virtual void visit(T6&) = 0;
+ virtual void visit(T7&) = 0;
+ virtual void visit(T8&) = 0;
+ virtual void visit(T9&) = 0;
+ };
+
+ //*****************************************************************
+ /// The visitor base class for eight types.
+ /// Derive visitors from this.
+ ///\ingroup visitor
+ //*****************************************************************
+ template <typename T1, typename T2, typename T3, typename T4,
+ typename T5, typename T6, typename T7, typename T8>
+ class visitor<T1, T2, T3, T4, T5, T6, T7, T8>
+ {
+ public:
+
+ virtual void visit(T1&) = 0;
+ virtual void visit(T2&) = 0;
+ virtual void visit(T3&) = 0;
+ virtual void visit(T4&) = 0;
+ virtual void visit(T5&) = 0;
+ virtual void visit(T6&) = 0;
+ virtual void visit(T7&) = 0;
+ virtual void visit(T8&) = 0;
+ };
+
+ //*****************************************************************
+ /// The visitor base class for seven types.
+ /// Derive visitors from this.
+ ///\ingroup visitor
+ //*****************************************************************
+ template <typename T1, typename T2, typename T3, typename T4,
+ typename T5, typename T6, typename T7>
+ class visitor<T1, T2, T3, T4, T5, T6, T7>
+ {
+ public:
+
+ virtual void visit(T1&) = 0;
+ virtual void visit(T2&) = 0;
+ virtual void visit(T3&) = 0;
+ virtual void visit(T4&) = 0;
+ virtual void visit(T5&) = 0;
+ virtual void visit(T6&) = 0;
+ virtual void visit(T7&) = 0;
+ };
+
+ //*****************************************************************
+ /// The visitor base class for six types.
+ /// Derive visitors from this.
+ ///\ingroup visitor
+ //*****************************************************************
+ template <typename T1, typename T2, typename T3, typename T4,
+ typename T5, typename T6>
+ class visitor<T1, T2, T3, T4, T5, T6>
+ {
+ public:
+
+ virtual void visit(T1&) = 0;
+ virtual void visit(T2&) = 0;
+ virtual void visit(T3&) = 0;
+ virtual void visit(T4&) = 0;
+ virtual void visit(T5&) = 0;
+ virtual void visit(T6&) = 0;
+ };
+
+ //*****************************************************************
+ /// The visitor base class for five types.
+ /// Derive visitors from this.
+ ///\ingroup visitor
+ //*****************************************************************
+ template <typename T1, typename T2, typename T3, typename T4,
+ typename T5>
+ class visitor<T1, T2, T3, T4, T5>
+ {
+ public:
+
+ virtual void visit(T1&) = 0;
+ virtual void visit(T2&) = 0;
+ virtual void visit(T3&) = 0;
+ virtual void visit(T4&) = 0;
+ virtual void visit(T5&) = 0;
+ };
+
+ //*****************************************************************
+ /// The visitor base class for four types.
+ /// Derive visitors from this.
+ ///\ingroup visitor
+ //*****************************************************************
+ template <typename T1, typename T2, typename T3, typename T4>
+ class visitor<T1, T2, T3, T4>
+ {
+ public:
+
+ virtual void visit(T1&) = 0;
+ virtual void visit(T2&) = 0;
+ virtual void visit(T3&) = 0;
+ virtual void visit(T4&) = 0;
+ };
+
+ //*****************************************************************
+ /// The visitor base class for three types.
+ /// Derive visitors from this.
+ ///\ingroup visitor
+ //*****************************************************************
+ template <typename T1, typename T2, typename T3>
+ class visitor<T1, T2, T3>
+ {
+ public:
+
+ virtual void visit(T1&) = 0;
+ virtual void visit(T2&) = 0;
+ virtual void visit(T3&) = 0;
+ };
+
+ //*****************************************************************
+ /// The visitor base class for two types.
+ /// Derive visitors from this.
+ ///\ingroup visitor
+ //*****************************************************************
+ template <typename T1, typename T2>
+ class visitor<T1, T2>
+ {
+ public:
+
+ virtual void visit(T1&) = 0;
+ virtual void visit(T2&) = 0;
+ };
+
+ //*****************************************************************
+ /// The visitor base class for one type.
+ /// Derive visitors from this.
+ ///\ingroup visitor
+ //*****************************************************************
+ template <typename T1>
+ class visitor<T1>
+ {
+ public:
+
+ virtual void visit(T1&) = 0;
+ };
+}
+
+#endif
diff --git a/lib/etl/wstring.h b/lib/etl/wstring.h
new file mode 100644
index 0000000..8019a29
--- /dev/null
+++ b/lib/etl/wstring.h
@@ -0,0 +1,190 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_WSTRING__
+#define __ETL_WSTRING__
+
+#include "platform.h"
+#include "basic_string.h"
+
+#if defined(ETL_COMPILER_MICROSOFT)
+ #undef min
+#endif
+
+namespace etl
+{
+ typedef ibasic_string<wchar_t> iwstring;
+
+ //***************************************************************************
+ /// A wstring implementation that uses a fixed size buffer.
+ ///\tparam MAX_SIZE_ The maximum number of elements that can be stored.
+ ///\ingroup wstring
+ //***************************************************************************
+ template <const size_t MAX_SIZE_>
+ class wstring : public iwstring
+ {
+ public:
+
+ typedef iwstring::value_type value_type;
+
+ static const size_t MAX_SIZE = MAX_SIZE_;
+
+ //*************************************************************************
+ /// Constructor.
+ //*************************************************************************
+ wstring()
+ : iwstring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+ {
+ iwstring::initialise();
+ }
+
+ //*************************************************************************
+ /// Copy constructor.
+ ///\param other The other string.
+ //*************************************************************************
+ wstring(const etl::wstring<MAX_SIZE_>& other)
+ : iwstring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+ {
+ wstring::initialise();
+ wstring::assign(other.begin(), other.end());
+ }
+
+
+ //*************************************************************************
+ /// From other string, position, length.
+ ///\param other The other string.
+ ///\param position The position of the first character.
+ ///\param length The number of characters. Default = npos.
+ //*************************************************************************
+ wstring(const etl::wstring<MAX_SIZE_>& other, size_t position, size_t length = npos)
+ : iwstring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+ {
+ ETL_ASSERT(position < other.size(), ETL_ERROR(string_out_of_bounds));
+
+ // Set the length to the exact amount.
+ length = (length > MAX_SIZE_) ? MAX_SIZE_ : length;
+
+ iwstring::initialise();
+ iwstring::assign(other.begin() + position, other.begin() + position + length);
+ }
+
+ //*************************************************************************
+ /// Constructor, from null terminated text.
+ ///\param text The initial text of the wstring.
+ //*************************************************************************
+ wstring(const value_type* text)
+ : iwstring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+ {
+ iwstring::initialise();
+ iwstring::assign(text, text + etl::char_traits<value_type>::length(text));
+ }
+
+ //*************************************************************************
+ /// Constructor, from null terminated text and count.
+ ///\param text The initial text of the wstring.
+ ///\param count The number of characters to copy.
+ //*************************************************************************
+ wstring(const value_type* text, size_t count)
+ : iwstring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+ {
+ iwstring::initialise();
+ iwstring::assign(text, text + count);
+ }
+
+ //*************************************************************************
+ /// Constructor, from initial size and value.
+ ///\param initialSize The initial size of the wstring.
+ ///\param value The value to fill the wstring with.
+ //*************************************************************************
+ wstring(size_t count, value_type c)
+ : iwstring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+ {
+ iwstring::initialise();
+ iwstring::resize(count, c);
+ }
+
+ //*************************************************************************
+ /// Constructor, from an iterator range.
+ ///\tparam TIterator The iterator type.
+ ///\param first The iterator to the first element.
+ ///\param last The iterator to the last element + 1.
+ //*************************************************************************
+ template <typename TIterator>
+ wstring(TIterator first, TIterator last)
+ : iwstring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+ {
+ iwstring::assign(first, last);
+ }
+
+ //*************************************************************************
+ /// Returns a sub-string.
+ ///\param position The position of the first character. Default = 0.
+ ///\param length The number of characters. Default = npos.
+ //*************************************************************************
+ etl::wstring<MAX_SIZE_> substr(size_t position = 0, size_t length = npos) const
+ {
+ etl::wstring<MAX_SIZE_> new_string;
+
+ if (position != size())
+ {
+ ETL_ASSERT(position < size(), ETL_ERROR(string_out_of_bounds));
+
+ length = std::min(length, size() - position);
+
+ new_string.assign(buffer + position, buffer + position + length);
+ }
+
+ return new_string;
+ }
+
+ //*************************************************************************
+ /// Assignment operator.
+ //*************************************************************************
+ wstring& operator = (const wstring& rhs)
+ {
+ if (&rhs != this)
+ {
+ iwstring::assign(rhs.cbegin(), rhs.cend());
+ }
+
+ return *this;
+ }
+
+ private:
+
+ value_type buffer[MAX_SIZE + 1];
+ };
+}
+
+#if defined(ETL_COMPILER_MICROSOFT)
+ #define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#endif
diff --git a/lib/libopencm3 b/lib/libopencm3
-Subproject 4864e9635d5ab4d20ac970f2d811de35d790ee9
+Subproject e0d34896bf2921f9ffaf3731a5d3cdbc4ca1286