Last active
May 10, 2020 18:32
-
-
Save flamewing/95b7c4a57ba1ab219042b88fb95e4774 to your computer and use it in GitHub Desktop.
In-progress update of bigendian_io.hh.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Godbolt: https://godbolt.org/#z:OYLghAFBqd5QCxAYwPYBMCmBRdBLAF1QCcAaPECAM1QDsCBlZAQwBtMQBGAJlICsupVs1qhkAUm4AhSVNIBnTO2QE8dSplroAwqlYBXALa1Bm9ABk8tTADkjAI0zEuAFgBsvAA6p5hNbV0DY0FvX1U6S2s7Q0dnTndeRWVw2gYCZmICQKMTTgUlTBV/NIyCSNsHJ0F5dMzs4Lya0vLo2K4ASgVUfWJkDgByAHoAKgBqAFph8dGAWQwOUe1ZZYBmKVGrLHpx9Pt5ccN5kFGCcTXR5HH7Zl9L1CoqRQJjlzP13fGAdzx0AiRRlwTKajYaDcQABgAgiMIZCQYtUJ4AJ7EPDABAEUYQbTtUYAMWEhkw31Eo244M4nHG5M4AA5RmdtFRCcSrMAAHTyOh4ZAAAWAhmYeFY7LQhjO2FhIKlYwAKgg8PJRp5iKhgMRmIYNkqqMRMJhRlyqARPhkFkjuhcRKM9fgaqj7PoCAbCKMROhBiRRod8FQkRtTlD4fotE4TggDc7iIYlfdwwaAOI2ACqo3MmHkimIowTmicbFGAAV9PZWDy0zzNIo3UrPCWy/II%2BgZaN7P6/ga8XqDQx7iazfjulpmClSKNMIQI9mAG5OXx0UYrUZxjsVvq0RRjkgtiAj0YWnrLzwpXEif3CKOjWfEee0dkylvyxXK1XqzXa0Z2ggOp2YdAbWh41GBBEUjBA91db5WFYVsDX0RQqH0Vgx0dQM4TGAB1ABJWUAAkAHlk1lUZIRsABNUYMMhAAlajSNlMi3lGb4/m6TFMFnQDVzwQxPDLP9mIyDV6H9e4WxmbBqO0XD6MhKQsPMHCKK9PEcJsbAGAYfF8Ookiixo2UsO0ZNzBootk2owt8IYbB7yDMYGH1ICk1TdNMzDXNrA1GDi1LctLHXasaGzQ49U/TB0mFeQ7PQlsyMtRtulYf9wNnG1CgnWd/2YC5EVEqhnJTNMMyzHM828ot638ysN0wFs2DoYBmMncNnxVNUNUMdlRiwgraFQAgx0UA1GQxAhPBAQZBk%2BGb2WAWh9HZEhgEGMtAozMEVlsmUwShWFJBWPAqFDArFKkAB9eSE2wGwABEsNI86sPw87cP27gViwKgrANM7Lqw667oemwnpet69r2j6rGQAwsAZFZtDYYASEncUtvew7aBh/Q4cZZB7TZCUMeh2GRoRwh8yIYgichzHsdxhGCCRTxMHO78hQIeQachWEptGGx9X/Ihwu%2B6xvREfQ2FYf1gtmBgADVtBig6jpFn70Agc6ZgYbRzvlyTcXEAB2JYTbV6wNfO7CbBWbh2n28EAE4VeOr7RnO86dNuyT/oTc6bvux7zod52nYOr6fvdz3qO96jff9oGg4BW3OBDg6zCOtOoddzACo9r2fcU2VZXMbAE8DkHg4h0PnY%2BiOxfzmPC5wkuy4D4GPdGHgVleav060TO%2B%2Bzk6o6kMjZTLgu46rnmw7Duvc8jj2x4n6PY87xv16L1vy47meIVrlYM6oDHj%2BJvPLvHyem%2Bn%2BHbrOW6o6n87t9L3eg6zz7F7F9vSOel%2BW5v1/jYLup8ywXxXtfde5074PyfjfeOwCPaf3rgaYB/8rrvxAanWmShFCfycKqbMkhpBImdMuYgWBszPmsJOMMZYCAEHYOOAe1p%2BrZnsGiFh%2BARDdVuqgUY/VMQAGt%2BqfGAqgcRwt2p9D/Pebg3BT4DxPrTVWqDLbnRhiIYAHtDYm2Ntoc2f5NbnRcn7c69sh5f1Fp2HS2gy5YRsIpdSUcRzfjwKhVm50oBsFNEieQ50rBlmsO0XEQSfpgLUd/YxWsdZ6wNig6J2kpIOKcY47AUdgp9HCdYMB%2BCrGoOSfYp6aSXE5Lqrg5RDsebZzdh7MxyCClJMhMXOO2h8I2AYMRD2bifzOg9lANAG4CChMSTYkirTzqFgshknpjC%2BleKgHWPUoymnjPaZ0ieAANQsukhk1EwAADxVHkips9D6FJabKNpHSuljMjlcuO0zqKSjWZHDZXTsA7Ooko301SXZ1JKRPcw512kzELApSS9yxY3HkEYTAEBDm4nQAI42Uh7CoD0LlYZV42A/DvliJFTEemZnhRAaceL0D2zWMbR%2BnwFTMOoGwRQlialH3AUYjRDSLHQoNLCslSKNgFQgGASASLcQe0dMKVQtBzohj1MwZA4FSwItZenDl6jNba11vraiar57WMjvyokiKJXnWNQi01aqPp4LOQfcOSSLWmt%2BYPWebKjp1LOtoQshZ4nUQYM9GwIdaCagzJ4RVBoaj/jRWnJ28E2SGm/JgTUvgABeZNH7HkoUdKgbM3hpyNvfXBGromW21X6/Vh8SY4zJtoKNZZ7DsgQNze1H0VTMAFDlKw7iNw8k1m2Z08hTSeDlYlTIlaDrts7QBHttx%2B1kIzMOuVrBGoTrbRqad3bUS9uQPOwdS79DdrcC4a17Kok2I0Y44FoL8LgshXqz%2B1aGbaAHYu5gngm0tptVUiG0JBj8wGgsfCLNaAJpDUSeQ4a%2BiJuyloN06B8CkhqPoB4H4QzqNgqlNQxAYp8yfEqT4JBhEEZatrRWWJtbjC6eYTooxgDLGkFiBtUaJDSFkLRrRpIIANtYzIaQnReb/vdBsZAyAsTxtJGeZcBUOzVgbRqVEGZ2i4f/fwhNfxnw3DdLlXiI4PHCkIP6cCyBhHNT%2BIsBjUhOBGzdHB6wnwnBMXpZob0qBpyEyhHzYWOV7OJvdBkdAY4sJWkAnweCmI9SHDSt4TI/hYwyYVNFQTNh8LONlOpLZJd0kQD6JkcY6AYYAFZaTjGQJ4TwrLwNhojTBhkRsZDVz5pR6jH5%2BpYzoMFQwbIxzCfAkqKWFxLPWcTShgqzAKXCmYCq0YwUQ58xVJgUrQ2bMsRAk6Wz%2BUgJUGTQQHoBpBTIFVEl1RwrNX1K9VsrZui6um0MWdr1Pq/UBo6aEhk3A3CSDcFHMrBhIO/fhoYmkRtwQrHMHN/951pwnA1IQJUEAYvOn/LqVAWolhsekNZ5T4OUtpYy1l9SOXytoD1MAQ9WBgkZgOIq1U4x4IdswGuw1YtvaqXUuda5kIcJ6xog9KQpcIDs0ILiZ0vELy1qZiB0N7JpejFlBKbFBzjkcMxTBQXmIDoHXdlDuBUaQAgDV4yWU0v7xbT1xSgwdqnYs/SezuiXP5Y87kvzxUgT6CYDfKwalDXznW7Zxz%2B3ju%2BfYAgC77w3anBe5Dr7su/vZTc%2Borz53AT5Chsj9XaPtvOdx4dwnp3weXe%2BHmn%2BNPPvsCs5j3b7Pgek9yt7UXql%2BarHodzqMDPsf4%2BJ9eW6l2oxRVnc0eV86DbIeoB%2BGzPRt3vuD%2BH9OUf6A2YA7JBSFwlIweNf/bPsfmJ4ckERzN1UqPltY/X7MEgBoxR8R5COASfw2GCwEugfQkYBHaAwgmbUcKDScEK8V5WTsquQY1YexYCRQwQxp9xOwi58TX4A4S6aBS4y6yhczowQGOz2j6AqDizCKsyb7Rr1axo1wSZNRwEEq4GN7nL2qFrkGUGPx8wAFQYGjAERRCisAhxQFi6wHMzwFEjG6y7IFd4HxEFXhz4L5wJwFVZRwgEsF66CjYEj4/CG7RTS4Sh65wHUHfp/K/oHx8wYp6CaJ0BND0BYgI4CTI6H7o5WZGzH7nLsEwGMi6EwQyAoHnJCEOH6HDIiDq4rCPy64gDh4e7uGGGnAIwOFjhOGSg0paFOx8wCzAB6YLg76ZCmEH4WYWGY5/6Oy2HkKMjiGhqjDhEhzoGYHWBxEpCjDHC%2BH%2BHeSBHpD0D2Eq5jiipSBm5sBP7y4xpUGRHd6QGYCi52GMxcESEFHVz7LOhK6tgq6CLu7xGyra7eFTGlH%2BCMjhEtEW7UEn66C0BhZYxlGJF75mGpF8aWHWEHxZHi6DEIEm4CFOxFGYhDLbFFALgVEEDoCqHEBP5sxcF1YyCdHe5sG9HQHZEDGS5Ej5GpzOEHy3HYoPEpDLHgkZLHBWbfG0rrE2EAkcE5EXGglWZji5E8Ey5SC0Ato3HfgYF3F0AwlLEIw4n5F3jKFbTlEwZ65DL4ApBsB5rUmcCrFP5jj3EhiPFEnUl0lXFhHwnIm/H/I9F9FAnaB4mYC8HDHnKjFHIqgTFYp8k7H%2BCQ4EoakCnLHG4qEgDm5tFdHg6t6KiUkJEmFI4pFo5HHpH/HSnnEgnyn0nXFoGkmYF2iWmATPGvEgBUDMqswkEdH3ymnVxnGcEulgnEkenvFekWn8mwmcny6ImcDilhl/ERnon9GylYkGg0lykKmCnulQnelJlUnaA0mEkGkMl%2BnMl0Csn%2BDsnBFVlclGmtGYCiljjlmal0DLHClEwMmhmomnE5kylFkEmxnKnjEOGfiJl9mzEEq9l6nUm1nYDcl1SmkaGupmmyhfE/CaCqBMzGG77JEo6HGyDkgnFSmAnOncEGhy4QkknxmYhwGBJbDHn%2BjgEUFxq%2BCkghnzFPlZnOwSlRGZHjn3kSFPnulCHvmHn0CGaiHzFyknBcEflHmGaG6GlqHhnnJ8zJiqAMLtgCJDLXjq4KKBlYz%2Bhh5u7UwKInACK0WXh7HnnmFHHXkZGRmYnRkwUhx4h2KpLOIZKPI3qbIK5jGqnMBOgCJEDmoIZ6iZgQCyhjBWC4j9RHJ9DHjImoF6i7bECARWDrGgVFrdEQVOlRkPk9RRixkCUpIlLCUTLXJTIzISUqnZjSXCxyXMAKUlQQBYSXhqU6W/mOx6U9BcSoDyXoCKXyAh53igQahUzjASgQCjLhkmWSmOx8wWrmplj16nlJE2kXl2lXngg3nmV3kA5prBn8y4n5my62WCUOXpJOU3LiUzlSUyU1hwpEi5VogWzKVjBZrqWoCaWYDaU/k9796cY6IWI3YGKcomLcoTrRGDA45Xp47CWE6eDE7u5k5KA/T7DtQ7BcHjAUoKbACkAKhlaeBnUZAZDAArWhURThV%2BaqDICaI3CtkqUpWSqHqsAyrmqkq9V4r17w7fhjg2BpV/E2oloXpapxK6pPWqxQB6jh7EALYECfU1CMi%2BGHr0BZocnB7DVvaFb8yGzeFwJlXBX2pzzPX6WARZrGU0HjisDViTV00HxOqBls0M7M101hUGWCJISsBM3pU0GnIEGC2M3fjqFHw/oUFUHgV8wu4gGFB77CZ6hi7/isVFVaiWD2AKb%2Bh4joahr0DMpXh2wZH0FAHnRSHCg0103cXAlWW3S5zSUA11XRmQisB%2BLyDyxz64mQWWVVbrkXDCCZijDAZe0Pm8GQjEDAD8EEFlkRTq1egc01yCH/lNTGk1U64vF6482KCfEsz82EHZ1oUswEpu2BlITBEgUS14W00VUYku0SE10e2DQnDB08Wx1unh2wpR2eAx2h0y7x2J2xmQmemYhq0qDbgIwd111ji4EcntKeCMjj1KFXEShjjR0kQJ1b3tH4GoFZ0Jq53IU%2BEF367vHBlcFl2n0AVfFwLAYb0H3rn31gVmVT2vmCJ0AZgYEIAzZWAFgZ3N1tb/1KoQDgNwpKoSWfYU2Pzk6p333/5/0wMIBQNoMAOfbwPLkFDOgoOOzQMAOpV4PsAEPi100AB%2BxDkDCD4U5DW5DddNnlAiCVI489t0mD1g6DcD72uIyVDJtDza72ZDyDlDNcrDR4lMnD3DEDIjH2/DEw8uwjn2YjFDzDGV4thaowowdBoagB0GTBoBmVztspPdbdlx8uWikde9k53Um9sZQhqtqdKgAkYh9Vxj0hIAs9VMjIXjwoeuwjy9gdQ9Y4m965m5HJWZaJFlORFjeZLpYdNjSodj%2BZcdB98M7pHVyuWKLjzobj8%2Bcxj8%2BT6tf4jIe9ETbpm5o5t5rd5jcTlj%2BJVxA9tjw9ldfdDjB9TjFdvjf4F9HTEhATrAeuvj89usdtzBgTIAwTwhPwu97TVTVxqhd9TddTuZqFi9nt3djTiTnT1jEdqT7T9j%2B9E9z5jsQhfT8%2B6d8xwzozrjfjC97tS9czgWYTpzh96MazLdGz9VWzXdZj9jBzg9aTSTY9mTPTCaVz50JAAzqFdzPjDz4z/zIT8z7zSzOFqzMTY5uzqF2AxyZTbzgL6T/dKT7zJzjj5zzjAS0LRyiqXhl9/pBeoajI%2BLLMhTPZDz/TrZlTb9bpQ52L6zE59VbLhLQduLJLLTZLoLnTHz05BhkluTMEpThT50dLKg2pcCKriOarhy9LrLBLHL6LfLyzHZax3zxLvFqA4rlVvdo9Urhz5LkrcrVLFd2r/TZFTgqg02%2BdTLASnrsWKqjI0LPLizJrO9suqAArpjCTqFso1rOztrTTrpDrILxzzrlL2TCr7lapyrNLXL8%2BAb3r7Amr8x7rhbdA5FHi7AhuCbvLidkTZrJpfxOjej/6Nt0GUa1SHbBo9tYBx9%2BF/6MwzB4w7Ub4hgXWSGu2DwGRBFRFhmM2XoosiGTUqsOUJB76LMGQSoVg2mDYmIK4XBx2sTSbezEh8snZI9Vj5zUJLuZ4MLBU9ZAZQZJdI0%2BBn9jpp7qFF7FuV72JeQgzlxtJsZt7AS97YkCMP7PJYJYRg5dZTJIAbhoxnhjIBBU9fr50KevV04jIUHXZMZw5%2BiZsd7tASID7uHl7tJjbudR9PxmZMbEr0ZeHf7Kb%2BRSdIx2bs5kxJHZH9wpbJTYHpH5HkHlHUgnzG5TbTDmVfMmxWlnM4wZY2BhoSI5thy3UUgNwAkC4aAcMbYPUKejg0EOUMwT%2BSRXFCTDhCp7HSpnHqpc5eoAAjoemFL6w2VsRWXQJDrjVfUhwqyh9Sfwe/RaxZyrlZ/K8Mjm3OROB2MQvMb4SuSkF5wjL4b5x4XUQFxKEF4Kz8zKZZwSdZwfDk7m/OSntBJIgSr4SUTMUl3WlfQl5WSlyrjUf51WYF/y189l4C7G5K8C20yxxk2c1mxF1x1ikcoqJzBV1feWzV/W%2BJ7Uzl1BXkfGza/U0CwydK%2Bm2C104NyHEV3OUWwEsLK534fmwUzq0W9WzgbWws%2BE%2BGx1wx1%2ByK3qyoCt781t710c/1%2BCztxx8N3Z9x5%2BVfqwGzKinF1N6d4S7q/SzV/i/Szdx81l5lT2zNh5xuI7TXJa1ZXxagUIXWI2OdNcCZngzDHARAPF4UKwObthVtKleyHjwgAT4qsImT3VxT1T8m7LlE7hcHqEiXgQZj9BZPX%2BQmtVcTwDVwSz/6VgDDOz9oDBbT9ValXz6gQL0t0LxcxXYpXgOmmL6T%2BTzL2wNTzz%2ByFr%2BmpL/cwb6wRz7KHrtVa%2Bylbz/Nzi497xer5cyODlHAtL%2BLyzOb4i5b0b7T%2BgB70r070K4t6CdjyFUIfIMABFIBF7xT3r6zwHwjPL8prH/H37977L0qhkMMA70NCn5T4b8l1ffaMmjGNr1uTz9DZlc76t/VVH83TH3WAQAn/Md78n1L2z6X3Lw75yG37QNn731b9oHn9mKMQXzT7RvryX2P74RXymtXw73X%2BBQ3291j275r8mtGp30nxL3P7L%2Bnyb7vyP6n%2BP%2BBMQNPzz0Xz3xf4v0msv%2Bmqv8ryFar5H9vwmp8KiECYgwf77yP598T%2BP/CmOf3n54wr%2BElG/qlTv4W8IBZff0kvyr4v8Z%2Ba/L%2BuHxDpq9zmD9JqI4GAC7tE%2BJPQ/sX2P4D98BVgUPt8w37CtXeOA4XqSGQAUCO%2B//YgYANIHACB%2BTA93JQPQH89uudA90rgO4S68SB9/BAf3xn7sgzAVA7LjQIj6Pkv%2BjAswKIPYHiCyBUg9cBrD4Eq8BBW/egRrwTQAkTyRAn3giiAFj8T%2BxgpELIILSPw22giAxgwRR6LkuY4FZHnik05KhQGq1dajYHSxfJ8cweR0MAHajWAqch2VAKOzND0AIwigeQKQBuq7VSch5CnPsAOw046ccfJ6g6nGTgoQUGeGSAwHOiQhFIkIBgLuDLA3BzoVWYXHoMF4MkhCnggJBIQ8a8U9czQmoSywkb5DzohQ8oSULKEVCJ%2Br7J6r0P6HFDShD0CoefTgJjDCwBQsvDbiKGDDphIeKMBw2IDzDFh5eV6AMKmHlD1hMjYgKMIILjClhbOFYQcOGEKtAkGwqmNsL6EXCy4VwoYWT2r6nDUC5w3Ya8LWG%2BhtseoLGLfRZiPCJhqww4XqABGaA%2BgoI54XsMmFvDRi50SEU4GhF80vhCwp4T8P2FvCKYiVWFiwGdDIxiASIWEdiIRFrChkkULyJ8JCrfDlhOItYcxQjxnDMRYI64TlluHMithrInYQyIpGHDkBjoXNHMN5FYj%2BR4IioeNwVSGBaRzdekZcMZGHCfAT/WUaKJPofRm8BUBUS8KVEMA7BujfRhBmcHNCMwSPJwTVjVzeCB2zdD/ooIMHON7hsLK0QSlQqVEnRJwq0Ub2Zo6MjR1WaDF6PcEWjoMiIa0ZozMZktZQvJR1smCUFNRMATnFsqD1YFmDwBGgnnrAjB7qC%2B%2BsYtAWHwW4A5Ix0YwermKEEMCmoQiNVomLAL782B5gjgZYId694wAx3HPjmNX75iIxjrKMa0yVCliCCQhdgJHVMHd94B6Y0hoyAQ5tix%2BpY2wev0wF4xuxcY8KCiMBHQYRxEvYYBYMD46D3%2BCTSMcuKEjlcNxagscZwKkHsMkqHY6gQuIRgHiHRFdUIAQG%2BiHJXch2XokeVUH1jsxjYmfpZjf62j9xS4h8QmgWwvi3xkWT8SeIRSWZtxafa8Q3VbZ%2BjDGBoUMeaONE1YfK/bTRjH3L7Doy6XYwej2LJa5jbozfOmjHyXSrYvxZPYdGmPPG38pxo/RkLOMd7aNaC7bYMXynQCsEgxGE6DEMjk5hj%2BBuze8WWMdh7dJi/zTYrcUu6TcMOX0TujUVfKXcjeNTG8QWMXFET1ekkrFLoGRAyTp6ck47i7jQDIhlJZJVSfBNNySdOxQE7SQYN0kwR9JSISEJmH6pTZmEJk/1nlCBqF4Q0QbayRJxo4aTCJkdciTXCcmt4MwRkn1lmL1wuNZJgUyQcFM7J2TRJ3Y4sZHVTBwIIphXWzkq1GDYBqxhmXQLpg1BxTH4jnZzluSWAn06aB3EHvUT0BbhPA8gPXAmMljA8iAY4HsaWNIBocGplbL1odyjYhEGiR4dqTMwGhViupvUscP2PqnOx7u84zSXeMym9jRgi0kKlFIYDDpw0KqDCC1DgRjcagyBRGDxNt5UTJw80radG1WlhSlQeUp2LtP2meSM0owPaZu3elHS/g2Fd7L1JwYrSMBa08fsBPElRTCwo%2BOivJISkBJuRak2yaFPqHYCIZBU4rpsWpFhg4E1UvAHqFQ5LSD4p0zmIyFNFTTZhXBQGVtAGmEynYxM86WTL1yri0RVM7ADTJCrN16ZpMqofELc41BkRucVEUCNZnszm6nMw5ONwZk8yMwCUj0SLMGk1wuZCMRmSgFuF4jNh8s2mY7CVmIxpZU0/4ULL6CvtNZHMumjrJVl284CJssWUNKBHHgpp0khVipOSkwVRZnNW2UJL1wuTDJzsmtkFLdmZ0PZ41TmF7LyhuT/J70o3gHJtkSS6AnskAG7SSl%2ByUp0c92bHLtkhyQAxUrqaVJRzhoKpyc12QrPykZyppX08rJHP9nFy6ZEss6YyEQiuDbe1fa2WnKJm1ySZCMBuQKSmnWCW5gcxWXQmpgIxq5NcBCu9STHece%2BZ3bltzLwBeDZZxwkWS4O7l65mBfcmOQfDHlA8mpiA%2B5tPPnytkVZSI9WVTCXldyUgU0teQ1QMFizqZI86LlOAJmmz%2B5W8lgN1LGm1cp5kPQ%2BXrIXn4iyA18tmcvIvkdStA681uU7FfkTzd5iLfeavSPlqy5ZgCscOfLiygK3mz0/uTvRHlQL35k8ved/NnnzzVZwyO4YvOQXAK0FKAK%2BUXK1m4Kd5n8ghaqx/lzzeZJC/mSfJIBnzUeU0rQazOLnAyRJp7MSQQSikBVjhBKXGfjOHlazvZTsyyS7OwWyKw57k%2BaJXJTkjzE5sUwuUoufkHxy5B0nRXfK1k6zQxeuJ8eBOhiQT6A4C/uaYranmLIReAV8VYo/E2LkF989uedLMWItmZwswBQIoiKIT7ByE5wYJODluCzKXXRjvs3W6OsZW9rF1kN0Vz/c8m/rK/vSycCvt%2BO2oc1EJz444cZFz83wpFjcysxkA04VeuTzgWhtbuDbdrmzPPhT5fsfEeCFkzgRA4Qca%2BYpT5wXSiydyKiZ%2BRPzHAhh/JAkCfmh0EXZkYlDQ0stPVyXcih8eAJTk%2B1S5BEn5Mch%2BY5iKUbynYUi2qSPJLnxyoZ6NKOYcsgXpL7qbjT0ehUKW6zWFMsyTsbKYk1KciMOTOZws9HvKEhASm%2BZzWMV6K9lnUvGQcq1lHKIleucRf/LOVgq6Zg8jZRAv7l8w8QXoCAIT2ETBwTYyOegDyhWB4grAWYLGp8pADnKa4%2ByhFVgsRWNSiAFK3ZZSo9L%2Bk2IbfMhf/LZgdpU59KmOSrM%2BWfUiRJAJEByrpXN1qlhCxmN8r/mbC2Y3y/hbCqwUAqhVac0yRkuuXZK7lKsimSzDgGwLRV9y4hVSKFA0irZvy8SUKvlWIrm6yKr0ANgGhTgAwxw9qaSoPjkqdl5qtOdSo/mOq05vhYKKaEoQsrJV6QS6p6v7ncqPRvK93PysFWuqa4Iq5hW8o5hTSeVVomVYCs5VmrOViqy5RqBVXvk1Vv8p5UatjU6tWyVoiVVTClUJr%2BFfytNSatbnVr7U9am%2BYRzo7zc7RAS6uKB3OiLLFOtUuXO9lTILLoZUYJZdgSN4ZlW1KMz/ucyimh4h1WSntTktnXo0R1vaw0iFM66Tr7Rcyn%2BqZLoCqBSc3QHyebR%2BjZhVlTXZDulzqnPznVV6uleEvtmhzj1XkGFamp1moKDCTMjMM3I8UmL4VLqjNY7HoU0qYFIbeuTwtGYe8l5Ks7kbYpjlAaP5RameZ3PA0%2BNINFChBaQpg3trU1uiulUqquXDrc1RCthRqvw6YKG1Jq5tSiWC4zLUZhReZbusQoHr4I7hLGUPP779r4OjG/dfoEPWsaDV2ylKeOpo0u99B26skgsvggM90V/Gk9YyUa56EL1rZBWTepHn3rM5mMgTextoWvqvFYGxuSAHp6M8TMsGumnaCliSJaViKt9ShuD7pAU1pqxpXQqzWZKblLMGruqs7LPLyNYcJtRkhHIibG%2Bgg%2BjTuvhlSbjNGK/VSev%2BkfYuNYW/HjJqi3Pqgpwmjdbi03XJN4lm3WVpmxC0SbFlBIqAU%2B3gqA8mYVmmNVfRZJ%2BA6ALZcrcKvB5dq51Jwu5YhoPkVMw29S7eumpjmtbV6s3dclGsilX9Alky/ze%2B3o7gVolom%2B1h9ydZbcklIcXHk1phYnCRhDLQDqCQK2rbhtCMfrdU31xYtpO/6GwIBmOCBkooi7bMMhk8D4pkMqGHtQhz1DXhi6ny/BSACe1zhWYr2oKZlz3KJYZsLBPbB%2BHDyIUatIoT9kFrE15bMCLuD7TeC%2B0ej5NV9IusCLfYtrAtm/WZdDsxCw6OIn2/1Y80YXva8d8OgneMz4rwdfCpJVHaloe6Q6sdHahjQEjh0vaPReMBVoAsZK47ntCO44WOoC1pbptdGxnaFoFk86yd2moGQiVyUs7ed0KlLQLrp2Y7hd5yTtQqmghkdZdEupHf6RR2vtadk2zddhu/oSbcdUsTXSTtZ186YFWu77SlIHUKbgeSmurU7FFRm6NdYu/HXbpgo1MT6VGj9tMqF1TrxNMO5ncmg92262dMCqLHLs2HejKdPnc9X50vUKz3d0sT3aTu91rq0pfusbejsF306VdJu0PQLPN0Z6rd8u8fhzpgpc6w9ZeyPdbqE2K7DdtG4Pdjpl3h709DeyvX2ti3S609Fu8XVnv90TazKfMQsKqGuClh/QIYBHO9O6pGBjw/gY4KrG4iI7FQZpVcKLzjA5QsNq4OgNLFaikhXQLAQCCBGShmlNMyoJrd1F7ABgQsQiWCNpiwBOcXQHo2dv%2BnwzMQiMJGczGRkMQQBmsJcWjPRgsJMYPELGf8QHL5gzVwD9gXjOxh6xwYeQYmCAE0NI7SZ4wcmDxApjwBKZzOreg0FCpA5M7zogoJEI4FY1oheNLGz5TrtXlJ60uympaapq1nuqXd/ckpe6BRzmpRMJUCXWyqDWyrQ1xw8NcSIFWkretJa8VX4TDXJrrK2y2tZnW61pzzNZXT4Bwfq0KSC2UPDVnctwI9Z81pGrVaBrFUJqy1zo6VQoaHkRElDFGwbZCWr73B/KUYBBjricNUAd8y6wrRkHgX5qsNUh%2BNbDgsNfLK11hoctgByG%2BbKNee6jQXuV1t6RdpugJOQcoNUjqDfGu3aMU50r6UjzACg%2BUr3UZHaDUepveNonWEHjdL5ZI2QfyNpGijzGgJFns43968jBRqg40Yl387yjGO2gVZShUoQVcJB0Xekc6M8qeIfEeg4h0YPrL/1zdF3KkcKNMaaDTR0o8QZsk0dc9BuqJUbvWMh6cdR6njZkbDUTGx%2BAx6HCaWl2O7muKepadxuKOrHRDpxzQySS/lxq5jiKkQ6yqtmkriDYKlQy/LD1D7Sjkh1nq8o%2BMAavjAaymcGr%2BM4bojhyjYznr0VIm1iWx5vTscqN7H299xsY4jrPWKbk9zB5%2BbiZWMCHnjCMc49zq91rGbKqJy477o5kj6KjQerdTicOMPGujd46vQOtJPHHG9NejExDoSNsmkjJe0Y2SeaN97a9HRyU6UcFM9GYmujQ0f%2BmoioBHQNQT6azkhAZIfgagLUHpwABSNW2/IBCkCoBRM91KUMqb5hjQHFU0GaJ8HZDMgn89AG6qKBRyDAaQWVcELSC9MrBBgIET4DsCiGyFFs8gUWMwEWyY0mY4wd0OMEn3hZdocIZU22qj7KnRgQhPrKXvnzvrZU623wvARVSBIRRjIGzQZoVQYKI2Dhe6W6gzNpnuYGZrM9UMz7t9zoeZgZoWYCklsjoq9csyvJACtnaAS8ms1MpTO6MGzzhJsxXWzOgD%2BkHZgs1fSLM9nSzCMfsyApABzmyN1ZoY2OfrNG70zyp5s8niH7tnUenZpc92a%2B2rntA65qhZBidDDmKFo5oJdUn3OVHDzujalrKb41Jasli5/0suevOr0%2BTLGv85LvpP4cXzqJd86yew3TmE0oecLYlr3VaaLzgFq8yWZAvxbpNTPWTclpSmblBjegWs9aYnMHnGzR5t1vDOW0LqALoC96VhdbJLq6KK6mrq7NzakWgwqZii1OaouIWAkoy/qv038L/nYZIAIC0xZeP9zWD8Jzgw1qqLsk7lOmhVfJYw5CX687F3DdGubqipKiyeUNOxeItW87DdaoBdBbwqwXC9iR8c5meouYdhL8%2BUS56PEuSXezxJ1S06uBXSLb1OlumvpddxEjqiyl7SwBq0NwyHLmlkK/WrMvGWuLg7VsJpytCKBjgYWTU%2Bdt4knt6mlsz6d%2BpObDGJNSQdWrXjGXNhvmfMPUMgB6C%2BA0oLAFKxcAjBE8hCC0IkKiA%2BplgusJMwPdlY%2BGYgGAeVpvl926hIECrmBIqxqw0sWxGQ/V9NLdKQJh0n2VWtkt1I4MzWM07h9NM4dlCz8r6JWzCmVv9mGgCgE1uvFNYRhrXepc3Zk70drT40CAx6BfGtchZIZjrWNSa9y1dH1Vxrb106%2BU3Ovfq7rtINmCMu7ScA3AwNzM92ltgQ27rD14IhJ1wrxG%2Bj0FFjuEfOZ2VikjiRyqJWeQZIiuUjbynlQthRUYqLhsMELnR5eWGaCHHKqDTOt1oPDylalMHip2RUfK0VPykLmV4ZUW9cFnsahWxPVwMbQlFqjjdcr42uqclEMHTf6bs3SbUKgMHohhqHQCo/eZavNTNh95S0CNHVAkl0ovUharNkm5zZGRy1bUBBWvDLeyhdUma9WI23LZNv2wA9ZKg2zLSHnK2z4fcJWmZWFvNUXEolD5MREDtfJdkboLqnsDomA2F85uEamNW0qCMMkUd9XDaIFqu3cUVvYJZlV9tY3RbkyQO4sFuTbJQ7UjCO%2B%2BjQOg3wbmIGO7/TjuYgE7kN%2BgGDdEI2js4i1epCmHMSM4PULeD2FemwAgowUEKUuD8lQIo0/q0qKwDcaxqeByUbAV7D4JdvU3JUQ6d9FPfOhg3Z7nuD%2BqZVbTy1NCIVaWlHClQA1J7pdzwBvZjtm24a6sHWxWilpp2CeC6FeyOik275N7fPWGvkgPtp2oA5uN7F9nBCHIHg%2BgCmksARijBaQE%2BLEJvfaUMlIH/90YIA%2BAcf297u5MON7f4pNUc7/tvO4XYLubIQ7ukEu8/fLv0BobVduezXcORydlGjQqG9wGbvK3z0N99u8mE7uPoqAgKPuwPdvRD2oUo94VOPZPuyolNXa9%2B0rZU0P2Cez9te7bHfvb2CECtZuofaEeA0z7cjy%2B9uTPSq3tbsSXWw%2Bn1tL3X0MjpCI1HkdaPzbqBP%2B3Al/sgNRGSDh4IhFAeTiwbUD2xzWNsNdw3Ahsex0A8ccgOy6h99xwg4cfghwQyDgHJOPgcLVgnERiBz44Ad%2BOwnyDs20o/Qc72hbWD0pCJVwfiVg73yMO8LDPukP7rLgaO5Q40rUPg5tDxO0ejKfJ2mHOj%2BGqw/YdWJu7F8bhzejvTD2CCY9gnv9UBqiOZ7MdiRywakdn217x6cx5oxRJWJPb39pe/04nuyoz7UzzRx7evsDU9Hd9wx69Ufv7pV7sNlwNM8lpWOQG8xWJ748cfXPEI0EZx%2BA9thuOYHcTx5yE78c3PbnW9iRtY4ufPOrnjjsJ8k/8d3PIn4D1xzdmgc/PPH4LtRg44eCAvwnwLr55oyCd/PEn8LxF0C6Bci17nhiaJ2bFidfMMk0T/51i8xeIucXqT/exLT4n%2BiXQouSm7eLPZF7/L8yqQAuiwilbvyKd/udneyetUxKXSN6uWAlvCxcwBAZSundjtVP478uYiAveUdp32eMz9J2hwD17iPz6vKEuy%2BdDURLdaOhWXy%2Bxu5OhXTQd6m5XGJSNxXkr6u5U5of135XPLmOYfeKfrPi5GDzmuq8Am7M5ynCOPqwifNxsdJjrfhNgADc6vMAz0RlzXCNe53nK%2Bds1yK/RlSM35yABgAqGNDvD00C%2BKGjU8NC9Xo38x4VH64zgiBRncloJ9VS2sCMu4EwcmvCFpCEMWaDILWUE5ARjBIHTb72xmYzM94PYP2eCK0u8HgPOloOMiz24QukgVS7obGWWzqKFYZAhWUfRO90b9xqXdNOsH5GQAkqlpba845bN4JYQCuac2Ny4kTdiZRXAiPVz5TJvUInzlRUMK%2BMUCv6gRjII92HRGDPvQQ5bld7%2B9lzp2MTf7ld1Izj4EAI3BKcQAu5wZLus3NVRsEdBGTBUgPQHlN2Jnzp6YPqdV76ilWGBBVUO4D%2BD8aHILIe/3lmIyl0RI%2B/vrH%2BieYqJmI%2BUfV3n9X9324HwtL/sQ5R%2BKO%2B6UMfdG577Gq2TII09oAEUCNzljYBpuM3Ero96EjHDG50BzHz%2B2ch4/CvMPX1RkIJ%2BDzTvQw1MerMJ7A8LoxPrACTwh/8ryAZPiD5TMoULQl4FPqDwZXSsPu%2BEwzXaoUMQDirL057XbjJ/3L3dRghovVw98e95dZPHK57i151WFgYRf%2BCKBW2xF6np2tVmwI5Jh06loi334nPRluITHfvC3FEiundfEtLXmyK1iE3SvNlGGvNhasEzqow1sbnl2JgE3SsCPKyKvFuZ5c191VsLwL9Xuk7YYcNerqvqrZ0ZAIyCGGHl5Myr5TJeU6rS1sh0Q/IYa%2B2H6PDHqRm33A9wJIPfGD7DB5yuEfEPP5ZTxmeGBsRJuGH/j4yDuspUoX8uPbzZ8O%2BruLCbEZb5R7iPjve3rd/t0O6HewPOPFIYHGO%2B4sMe%2BPWH9T3PhSrw4nQon1N%2Bm5M/SfaMcnu7xO/VRf3lPwPtTwjA08QAtPVCNFBD/0/OhDPxnzN3D7HBlUDS1n57%2B97s8jzD7T3iRjS45nO3aUKpxwfxPpd8QldyNll4YNJBSA0QYbnhLQAjdRutWouPXKG/Dccv8Iby6DhTpAqTnYKFdSwIwnYAC%2B55QvqXwSlOPi/UAavkQML%2Bl%2BdygyVapG%2BLk3WzbNi5Ffr6DLlKzaJ9GYJwLOGt92jZtBv0a5iD1%2B0BcI7odgMQA07s0nXTLoNwYNPc5P43eDy99inIo2vKH2Ru19U4de5f6ar1S3160RnWu3XJ9D1xj14viTQ/Ar/O5H%2BwLjUY/nuCSlQ/tdyuk/h9%2B31mFnDp%2BIoJzrP95/kFYDI%2BqNwWyFXz%2BR/Kzt7nBqIyCrZHE/Crp2FIz0oEo3fQUvXNe41jeqSAvqsq9oD2NxUdr/pZz0l6fepfX3yXRm9tYQmp6WB6UAgM6bxk416fQK6m3pU5CFBGyCj3QR%2BY7%2B9eCC3f9GbgWYjRe%2B//a0RnF//fV3sjI/x2BO84ESf0IsQAKLzAE5/YgAX833XrwgA2IWjHNwtVdf0fcUvF9z6BcaXf2Zs5xRnxb8vXWpBbx0EF6Ffg24ROCDRq4IQk99OXfa2/J5iT3298tAX3399apbXxABhfLlzHAWAiNz1cedUYDHBlfJhBwBJfZ0GeguLHnyahPfbgM%2B1V3WgIDd6AniScAmAxkE4CF0SQPh1eAjYDF9WAjl3YD8ifnyEDI3fCGVNSLWGmYcBqQgMQRSAytAoCA3KgMQoTBGQMF85AxgM04lAzQLYDqAjgLcCVA/V3UC%2BfYAE98DfIwKmUxAoqQDdVA6sAJQ6An3wUCXA8mC8DdXHwM8C%2BIPXHcC7AgVQrAVfQQMF9J/V80qR13VXXmUAgzTiwgGXDOhVA8AClGdAd3EKj5gEwbQEMRhMWA39dKYVCSX1BQGCB04DQaiX30YuK8DnB/ADIm0JjtQWFaglQZ7X8BLtOWHIxhMIyCVghFay0fJUbKIIYCnAR/0UNn/ELxaowvKRhn8sIOihDRWAT/0UYvsKwDHBlg%2BQOzBS3e912sb6fXUy9A1HL2H9A/SRhttZaerClsDgxy2NtMwQPjUpXvO42FQB9cvVj1CdPY03Jy3JryvofKClCBFwaABVHZvwf4TZhYPat3GBOAHQSwVs/ZumIhlXBWSc9eiMrBsFPsRAOVAIafN02tPDba25si3LECBDu9OPUpNevcEKT8D4H50fgrg9kGL9hnTz3P8TKVmgD8VXGuDZDuEdXw9NaAaP0z89FLENZd/SaEJEA%2Bgdz3JDMAat2pDU7am1xDm/eviD9BrDbTQRZA6IIAUBbJ/1QJ8/bYK6pdg/YLYAjgtRlODQgxwINCRQkQC1U9dEgnuCO0R4Kr8AAw%2Bw5DIySs0D5IA6AMZDFDFf1VCebEGVqD6gujHKhr8WMDaCCwToLMxAGHoNtVxgugEGDVqfmBGCNMMYP6CFwWWBmoxwf/SQN/wWYPTCbfHULxZ9QlYMND6qTv2bpTQ9IHNc3/cAOEDLQw4OIMv/L7B/9zg330dCnzHELYAtVanTuCRgB4MGAIQtOVW83gqQA%2BCrbb4POl5eeAP%2BCSTQELr0I9fVy5Ml/JkMk4Jw%2BlV8I5Q2EKzQxwBEOzQHgZEKrdKQ9oDRCMQmOWFCOQrkKb8pQ9kN5oWQp2DvCA3MUIlCeQwUNmcelNfwJDkQOELHBiQwcKVCVQwhn3D0AGEIVCf/C8KZtQw38PmCRTWXCWCqwi4LWCbDDYPspsHDJDC9mw6Lz2CowA4OtDv/J0DOC0I3sKuD4vEkO9UX2V0NHD3Q8cKT8OQrcz94fVALBgDgw%2BAI89kXNVwydzkTdzWhqg71z5tUI%2B0OrDUbNIBlExwbM0rMzzRclXopIyvnaIUKG%2BnV4GwjD0Kcr3M/iUjNQG0KfMewsMCuDdw5ujpsbgSoX6oVQ3UM%2BlVRZkiv59dYUQBFNvOCL38l3QhisBT%2BG9xS4eBYfkciI8fzwpD4IwhkPsZ/f0J84fItFVGx/IvsIQiPXDV1EjrIwyJrDoyKQBQwZIls1A9ZUBc2WIUMFSMfhqddSM2Cz3RsPLAdgs/lSiT4AfwMiKIoyIDcTIlhiJtzIumysjUKCqLsjfDEgj8jqYBdxcj7YNyN5CPIocz95mBSKIeBoo3qIQiL/V6lCigpYaIiiuo2jGMi7/EGTTMxI9XycDVg6yKpMaLZdTotOImw1dE1IkPyKjcIkqLEwyom9w7DjggCHIjxIi4Jijq/NOwtCiIhiTYj5/DiKDCbDFfzHAqI3JQlN%2BTSvWX8bw1VwekDzNaJEANo5KKspdIwwHSiAkLc3kiBSRSNVE8oi4xr4sIzG35czQyLw/8YYtRm7Caoy4IDdqIyhwACzI2KmajLw4XHqoYY9qLc0DQLqOcjMAyD1H0Y5FsO/FV5eaKiithH6OJipXQhjYh2QViN8JuBAgV8juY2fkwDYo/iJEiFglCMSjCY1Gwqi4YzDlPNso6klyjhyVSMuMMYkW2KjNIqRnZiIACqPxiyIu0PWiHQ36IHCy/MmMaiKYomxaj6qNqJQB7IzqO5imYwKNcjWYtOSNjvIsWNGiARRaL5jJQmOUFiHzdvj95RYygQWiAo5UKpjlopCK592/BWLujffVG0xkOAjk06NuvVskxlUYgqOOjsIrGLOitIyiA/8840iK7okovsJJibY54K5ouqeQFTQCUMOOr5UqAWKdBT%2BRXibi3sdYAmjCGX2KhDfKTMGcMnvHqNTQWYoOMF8eI6WK1Dyw3inBivfA0PTi91TOK7VkLPCxzjGQPOK1j8oo6Lz8TolT1LijYiuK7CzY6uKtipXJP0Hj/SGTQJUvWJwDgCnQKePV8Z4hOPv8EoysNTjNoo0M2iWLYdT2jPo/OP3jdYv21OiDYrqiNiro02KrjCYmuN/9SY%2BuKdh2YwiKcBiIgMI%2BitwriOfjeY6eIS8/ohozlNG9IGNnivbb2MPgtRBfSJBOfWtBysnrV1gTQ7rEGALNXrEqy%2BDWyehNyDMTOCySj3fc2P18krBezbUGAXoEKii40LxLiLo9AE4AIAERNYxrooKnrsk7R6OpsigxQBKDkgkABmjtAJOxSoMEyhGmtREmnjUpboi2OrDQyUhJWijdORLETMYiRIgThYGf24BZE0RM7CAIARnlw7rJuwadJHVRPDdigzQO0SvEyuz0Tkdd6IMTzrIxPzxaAWjF4TxtSxMTiFBT6SiTQEnCKPipE45xsS3ExRM8T6HRh18TXqNRMjdAk3fgu88k%2BGzeioAzBJsTjEmJNMSIYg0IsT34%2BKLliakg%2BPEStgyRPNDd%2BWkBcT5E/SI8S6HegDhsVEwpP8T1EkpJ8oyk4ZPqdQk3XXCTF/NpO%2Bj%2BEpePMT4k5pNljcyOhIGtoyNpNSTi4hxO0ifKGwD6T%2B/E4JiS83JhMUiV%2BKjTGc/E7IICTNEoJO7RmE6axuTbDSpMDDtAJZJMSVkyGKaT6fOKM2Sk4xYOsi5EtePesnLN3Dj5PRfnW1j0Yk0MPjsYo5I1gskhRIuSvQtOyKSNEkZi0TSk2aP0TFkqJOWS4kujgSSP4uWP5saY3oDXjSrQK3dx/zOFL3idYxFI6T9Y81ykTTk7JIxSkEkILus4WL6yvpnPSFMRlEbBWX5SKHAwEiDxk4pKeT8UnRO7QiaT5OqTiU35NJTaUSaMdhrYiCKFSAIokPewSQkCIMBY48CN5DD7DUJwC54ttVugz/dpLsTOkzSPwiKYGRJtTTgNxJ/9lE6uwADsUzQJvjC6BZMZBXUlKm4i/kxpPG034wFJlinaI3SDTC4%2B1PZTywJ1OdAXUnGndSzY7tCBtJU%2BqJrgfUzRL9SAyANIXpbUp%2BJGR6k1ZIuDQyCNJmcgU6NMqNY0u1L1jwEpsLnwy4imGcSg0tNK7pgk8pzrjBQ3NNxT809iIiTtAetJLTYkwmMrT%2BYyNKtSY021P2T7E5tPxR2Y9tNTTron/wrse07NIPh%2B0vXEHTC0kdOLSQ09VMLQq0viJnS60udNZT40ptMTSW09mOOcO0tdLNi7rchyvjvUmVJxTd0j/0JTA0w9JwTQ0tZLo5T0zUNBiL0%2BG3nSHUxdP/B70iAEfSYEjgLIcGHLNKT8d0sAO/SwkqpOHTR0o9InTw0qdOrSo0nPzAzbExtKPik0zAF6S4MyuJBsZkzdJQyP031PQz5kzDMX9sM/9OPTboYDMtTQMuC3rSIMhNLExyMyjNXT4MmdBGSvU3lNQy90ljN/SKknDO/idPIDPwyz0njJ6ts3Pqx2TXaS9K78kUkuPIyTkqjLPiu0l5OuTUBDJAky%2B0hjLzSmM/1Jkyi0uTPYzcMpTJDjPXQjNb87WJblRtXUiFN%2BsoUokUZSFdeFJIywE9JMgSP/QzOXAzY62K3SnYKTJsyC0uzIPSHM0tIAyK0vDJczM6GtKIzP4v5hqBaUr4OctV6QUyCy400jORTW0gnwiyf/aLKT8hCCVM%2BtoyJz2YA5CEVKn8DtUul5D6s40h1T/wwwEJCIAI1P0BgIg1NAj%2B43kLiyIAjDK%2BS2MlLI4yeIgJ2nSyE6giQlOJNn3CgTGX9GESUkqEHz8pEmRLRSBkvNxysM6Q%2Bz7Y9cVDMjJnk%2BgEzS5k2zK%2BSfkupPWzvGSgK5cAUltn4jrU7TPz9yMlNLdSn0ruhytsjCzJDgzsrOSsyB0%2BLKHTWMv9JSzQcl7OoDJ0pO3EdlsmWPwCCocwOICsERbQro/Az3zwZQCc7JlTg2KZlxSJA/V1EChCfgNV8A3fHOeyichGDhybA17MEUTAppxvtzAzBGAQrAnHL0DBfWnOmYik4nIJywcwX1sCvyCnKV9CAAQLxzE%2BYXMFyGcknMJzBfcIPRiLHNJzZR5nYmCxhSYAHFnA56TCNURtcmtABwX9FlPdQjc59H3Yv0OmB1zvObdHowISKGAtzaE5AWtyn0WtEeAUY5wimg/BAIUywtqZGDVB2AK4H%2Bp0AWnGzpxgHtlIBA84AGDzY89UzYBI8gxnGArAcYAjAfKOcFZRmrLiRgxUSZHn4RccmnIzo6sxVPW0X0pDOMprAvnOADec9X3m4CbGKWogZE7IyTsC%2BURlExs0w%2B099p/eVIlSUqDvJ9FCMhvJqAm88lDTp2NXRJslj5NnXbzkATvKxSA3HvKmSEYPvJp4B89iUyph8ggFHzTc2qUnyJOafL51Z8%2BfPuT1fJfMX9V84PHXzM7cCi3zR8q3JXyM0omj5kiVGfK%2BwO86Ny7zF8vFOXyFUnFQqTr8uwU3zJbRvJkSCYUQBfyujY/M/yF8wX3PzpkrGgAK58wfMyoxbF5FLjB0bfOcSW8p/IIAxgD/IXsv8uAp/yL80vP7zkCjfPAo0CjJDvznEvXMJ198yAroMCC54KIKz8kgoQKlUwAqWyqCyZFxsMCxvOcTd8hApuyp8xBQkUWClF1gL2Cq7MQLyC6kKyzqCgQpHznEh/L/yCAUQoPzxC/%2BQuA58mAtPyRAeAsfz/8%2BQpQLeC5yn4LaClnntymCxHUkL77AwpMAOC4wrkK18igpvyzKO/JWA/eekMJ0cC67LZgb%2BNRnsLdnIWm7znC9Qq4L3CoAtvyQCkfO8L6C8ZkYL2FLGl8LtwaAsILpCwwoiLL8nLGiKeCzwriLt87wuEKXCzQsgK0i%2Binfy9CzIscKjCyIqQKFCofKKLqIbwrULkipEUqLgimotYKsipwtkKoipouAKvKRvO8LwC0ABSLgQqAuqKT8sZOIKBixorMLCikYpHzjnI6FdyMi3orqKcisgrcKhi2IpWLt8tYvGKNimYv0K5imQt7zdiq/PyLFaZosOLqIY52%2Bh2AYUW6LZisIu/yFi0wsoLli2SkbzjncYteLNiqQu2KvivYqWKQ4LfIwgZE1vO6KaMxAqvBpwbNPCKjY0TGXokSiEurgoSmRMSKJ83AsNJXtWfPhLo7JEujcUSj/zRLES/Yt%2BLu6GoGhKIAUovULyiub2hUiShuwRLpwUkoXtySsAUpLOS6kshKii%2BkvaL8SmyUJLqi4kqrsuS54J5KCfPkoxKfiwUsOL6S8YpCM4S9kpJLkS7/NRLkAdEoFKsSoUucTW83QslKqSsku1KKS3UqpLMS85ChK6C8fJELn8lks2ETSjUqlKtS4gp1K9Sm0objlSoQtS9HS%2BGxCNXSrrOlLNGWUoRR5S/UttLDS7jHG5AygkrsKrS0Mo9L2Cr0utLFSg0r9LrCtkGDLKSlMvNLPSy0u9LMymMuVKxiq%2Bi6KyiwIqJg2Sgsu5KLS3kqtL%2BSn0tH8hShIodLqyoMuJ1gTI/IlK3Ss0obKiypspLKPCpUr%2BK6SkooDKuyw0i6K6y0vMHKZSxsrlLmyhUrHKsyicoIAMINovjKZymyTnL%2By%2BsqXLhylctHKYimkswLtynMogKeymkz7KQyhcv5LCytMuLKMy9crLLNyjCGOdcShMvRh5y//MXLwy5csjLVy6Mt9LPy450ZL989UqPKgKk8pAqzygovHLaSrcuOcRSgIvAz/yjkrDKCCCMryLEKu4uGKIK68tANDyx8pwrUCPCqjLWyx2ChLjne4FOKHygCqfKhyl8pHK3y88uQrLy%2BipOKUYrCs1Lny7IvTKWy0svAqUKr8uoBhQTACBKyK5iooqQqKitAqaKuipIqZKpiuwrUyoStfKRK98rErLywrDHz9c38slB%2BK90ujcpGV0DgQ742qCSI3PbgoUrgK9YQIqGfLipikMIAyqgrRSkytkqNK8yq6pLK%2BYmsrCVR%2BPsrm6PCsIBnKkGIvK3KgyvQqNComhgryK7NIsr1tIKofi7K24rCrHKiKo4qkKjcvEqDK8YsSq5K5Kv8rUqvC3vjbKvItDDwqruh0rOKlbNZ86XVvFQBC8wX0lJIQfPNQAqcrIPV90eEvIAq4EcvOiZschNBlz5iHqs9968loubyOdWEuBKHCi4uyKwSm4rAq2yh4pxLOypkqdLD81krOLaipav6KrikwvBLRK9as3Kd86cu2ruy3arj0Fq0IsAhwilauqrlKmarjKz/a6sNJbqvxnuqFnQ6vqLci0KqirXKkfLAKe0CYu%2Br0i/aq2L/qnYpOrVqmiqUKrC/wviq8C3QveLHqz4uOrXChGrOrHYJGpaL7Soyr3KtC0hWYKeikEthrnqoGrDCQ4AmoeL/S1/WMrbCiQoprFqj4vmLsawYsRq%2BC1yisK4q5kshrJ%2BNmoeqVkgGuuKXqvGvpqLq5xNVLJi8moxqxauGpxrJa3SvOqUK1op8KNwrIzmrcCoIt%2BrFXUEq5rFivGq8LDKhgq8qKi7Wrfz0a84o5rLi3/MBrMq4GvyrMCzWs8qMKr6tuEDy22oOr7a5auNrvitWtoqWinco%2BqOi72utr7ykIr%2Br/ao6sdqJammsQjXa0YpIqra3sr2rfamGrjrxa%2BGtVrOKlOtWKQ8T3JlE3iu2sxrOahOrzqk6rLLvzji8GsYqY6w2qprA606uDq66ySpeLcog2rVCW6qupVqa6%2B4ouqAS8GrUqm63upzrla7mtNqhSmEr1riq3ytYqtK9ivqq8qj8vErNq4ms%2BqxSm2vzKkqwSqcLhKtcoLr16y8pkSPa1GsTLo65Mv3ql6w%2Bu0rj6ter0q3KmRIFqnS8UvUqBKu%2Bq/SV6x%2BsIqDiz8rBqbC50p%2BqfKr%2BuPK2K08tyr/66KrpKjSvWs/qzK7%2BrQzf6tapDrsyn8pJq8ym%2BpKqD6n%2BqgbV6mBpBqtyxmpNJt6iTnJrTSliogbl6ghr/qXKwupIb3q1smSLKGgcuoa4KyBoQroGhhtPq3K2WvBrsGqhvkqsq%2BCvwqeGl2r4bJyrWozqGQ66v1qwGpBpob761Bteryy82qSLLa28sz1d6nBsXrlG/Bu4bCG3hufrpGi%2BuZKfavetwbkGo%2BrQaoSsOpYatGyxr0bwGzhtoajG%2BhskbTGrcorLgG5xuEbNKlRroa7GoUu/Ktq6CtMrAK3CscrqKmeuVLIKq6oibFGqJsoqYmpSribiKt%2BswrkmjhuiaxG2JvbrQmkioXrXGvJq4bxG4xq8b1a7irgCS65SMibcm1Jvyb0mwpvia4A3itLqGmkRrppFKyKtprGGiSueLpK7upybumnNLSa%2Bm5OqkbUK1SpGbEGlJocrmmyZtrqhSgyswbyGkpqUbNGFKoJQ0qqqqTrYs7KrqrPG/pumb3KhksSavKzZoWbTIsqt2aKqmyqjB86ppvKacqyptObvG85qybay0ZtKrhYAKsfg9mp5oObHYWquWah6gquKaumv5oEQAWxKxMxXcYKoyqaqo5vBb9oRqq6rJqgN1hB%2BgToBGZ%2BgQrH6BSAEwH6BwQIltQAQAfoBKpGMLkB6B1xD6E4AiW54FJbcWzoGEQQAFYBWB2QHuHBBuATgHBA3ATltpAXAEVsdghASlpcAiWwwC4AwnYlspayW0gApb%2BgIlvalwQUgGZayWzoDgBYAGAEQBVZXiCkqyACgE5EDW33xABE6ENDakQIQaGeKowdqTRV5Wols4QQ0EkUpbGWxIRRwiQegHwhaAaWEdbSALAEFBRAdgH9b8ASq1UBZwdqRZbSAI5EKBfwN1qJbw8fFoVb5MDICRBdALAATb1W1EGlb%2BgRls6AaAegCYA2ADgB4B%2BAQQGEAIChA2kAhACA3gBOgREBAV%2BgcYHwglwcYC7ZvCatssIJgY6CiEiAPiDx1WABM2VDKEMMHGAS6nkAIA4zHmQTRxgDCBZhg%2BRCjEw52gbDnajkdmAmAMIK20jziQB%2BFXat2srkuB00VUE3aLNFgE3au26zFKw85PcDnasPadv6oH4AmEwI72r6nGBqxC9sOYDgXokVQ%2BgSOjvbGyarQODpYdtv0BysM8n/A72pKl%2BASAUdlRAKUZAH9A528zRVQw8xtp4hteGYk3bH8S/EJE/wK4GEglUDMGw6wOtaGvww8lkk3bc4KgC7aqOw5HZh223ojwBN2zrBHBGOqq1/4kOjCBXQCBN%2BXGBEQTdq6x3JUQBTznc/LFP9N2/qHHaSAQUCna2sBhHzAYIOdvj947DCDawzqPGV2xE8mDuzBlOkWnyxURKESBFN2vQDDyagJEGDysPEzuvAV0DPLDz3MTIC6lN28NAQwBIOdugI%2BgL1rk7iQTdttBTabYG94lQOdpJxxuMdowhGwHynK452vb347rwZkEs1vCbgE3a4UYADj4agOM3mQPEX8Afg0AZKGS79AVLpikMu9xE8QcujnWi6CutLqnbekLLooZboVjrrtwuyrqK6au0ru8J2gldGXamuwrvS7Wu7Lu8J2ENOwq6eu6rsy62u26GWQDQYbqq7x24BiHaiQViHQAgu7rpm7IzIdrgJlulLpm6ylYgFRA4YOdsoSDujcGYBtsBTkxRbqdDq6xU0GYmW6QweCHw7RiO6lRB59A7qKtMwUrC%2BpN2rc3baG6zduPaohG4Ejz9O7kWvamDFVtetl9LHy0B6gXIBjatAFoEqA4gUgFCAgOmHpCAfAIDoR6YgKoEaAIeugBKA6gPQByBqgPHtSBagMoB%2BhWgHHoUByetHsaByerHraB0QroDpbS2vFspbCWuVujalWw5FpA3AcYGPQ6MUTCxBSSWgGERcQCAFwBCAdOgZaxwMqRu1ewg6HRDLyaQCZbHWrVqQAmVMiONaL8Q1tMBWSEgEEBC2xgDflS2lwFIAf%2Bd9ATb2eglqJaSWhVqValexMNGBee/nsF7gAYXoFx3iMXvaA1ellpk92Wzlu5bOWkPtD7Q%2BtwHFb%2BgSVtIBpWwrDVb7e8lspaVWkADVaNW3FtIBtWvVt1604nXrzk9e6cBupIcTgEdhzobgDKdDkY9FIBbWucEoB7Af1uda02rNrFAvOn1r9bo2wNu0QQ29vpBUigSNv9bY2qqyqC82xNrdxk2oltTaSRDNoGB3W9xFzb82qvr3Vi2kNrLaBAXgEraxASzFra9getsVal9D9SGB8IJLsGBsAXCHkAxMQYF1xL2mzEGAWYaMEVAarRbHB7kgSHrMA6euHosBKexHvR6wgfwDf6UelIEZ7qe762KBaeonoaB8gZ/vx6Gez/ux6kepoEJ6ggWHvgGKeqIC/7me2lt6A2eyPs56E%2BxVspaK%2BwEBjAC%2Bq8GL72QMvqxApeqmDewVgADnl7DW6gbtgVeqQD97NWjPs16nQNvnIBKAbPqqBeAP8Gl6ke43qX6zei3o1AJoYfpt6cB/1sd6PoJLuokCB70HkBiB6cFIGy%2BlgdZarqXfiqBYBfFuj7Y%2B%2BPukGk%2BhQBT71W9XrZaOWrlu4BaQI2GsGeATgBWA3AR2CNhrMSPpWA7ewweVbTB/3oz7dWzPogAkAHgaNbuBvPrNaZqKVRDBhEKvulQa%2Bh1ujaG%2B11uH6PWidiPJW%2BpEFDaf24NoGAFWsNvVoKgmWWjaB%2B%2BNsSGk2/1on702o4ESHZ%2B63oX6i203q4BeAAQBWAhAbRBQBN%2B5jB370O/fpba22jttugr%2BiYHrQPEB%2BB4xLMKjuvAyEBUFJBlOqIS7bHYErAvxb2tTtDN7%2BtkDg6BoAaCPZJOqITu7FAMPIyEfAJ/tyH1AKHp0AwB2HrMBABpHv/7f%2Bs4e/7MemAaZ6IBo4bJ7SgN/uAGoB5oAeGgB0AcQHqgaAdQHYBjoBZ7MBoEfxapB7nvwG%2BegXsBBYDL3oiGJeygZl6aBuXpCHsZD6BWBcQaluYGvB1gf8GQALXsGhc%2B01qqAmh/gapgjexfrqH4gUQat6JB7AfcGIR/oAOglweQahHBe2EdF7xe9QZk908qhEoBzBqwfZBj0YrDD6w%2BiPt0GpWkADj72QcEEKwPAFwG4BHYRwY8BaQWkFlGueh3qMHVWnEfT6/BgIdRGghk1oV6qgFA2L68gavpvBa%2B%2BvuAYEh91ub6Uh31rSH2%2BjIdjysholpyHe%2B/IYVbChofvdaSh6NrKGp%2BrNqqG6RoQapGGhkAHN71%2B1oYsIt%2B9qUgAG2vfo3BKW7oYGGXiHLuWwe2qTv7b2AWcCHa9QEgCoQe259uq6Z2qYYPalOjCHXaNQCYAXbPCcsFfb0uj9rnbvuk4uw7FQd6TQ62gzDrKJph2gA07HO7TqoG52nbts6sAezs06nOudoa72OnoAXY529xDfBPABAFu7QMUDFUA8UdNEg6J2lQAfabgWdowhDu8LvAgUUcRAA6B4ZaxA64UcDsKo/upwAB79gBaGghR2JrVB6giQ4YFINAaHtuG8gC4a%2BGrhjHpSA/%2BwCf8BLhknsgGXhhAeJ7ceiCYJ6UBioEBH6e14Z/Gaez4YBGmezoAwG%2BgUEY56GRzUf6BXe6EZEwxMUgfBB2QdMkl6De4hFl6EQYkeome4TEcsxuRtgfxGOB7XuCG6JyMZjaqJikdqGS21wBpHxB%2BfrBG8JxPqZGPoQEFZG3ewEBQMu4R2BlHyJ7kc6BeR7QZt69ByMfknHYFwBWAjYQrH%2B8QcZwb5aNRsSeT7U%2BswdIBA%2Brlp0mzR2kG/wy%2BkUajHKWtweMm8BzwbT6ZPfFu4BRJ1yaUnSAVMJMAXAIAA%3D%3D | |
/* -*- Mode: C++; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */ | |
/* | |
* Copyright (C) Flamewing 2011-2018 <flamewing.sonic@gmail.com> | |
* | |
* This program is free software: you can redistribute it and/or modify it | |
* under the terms of the GNU Lesser 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 Lesser General Public License for more details. | |
* | |
* You should have received a copy of the GNU Lesser General Public License | |
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |
*/ | |
#ifndef LIB_BIGENDIAN_IO_H | |
#define LIB_BIGENDIAN_IO_H | |
#include <algorithm> | |
#include <cstring> | |
#include <iterator> | |
#include <type_traits> | |
// Need to define manually for MSVC. | |
#if defined(_MSC_VER) || defined(_WIN32) | |
#ifndef __ORDER_BIG_ENDIAN__ | |
#define __ORDER_BIG_ENDIAN__ 4321 | |
#endif | |
#ifndef __ORDER_LITTLE_ENDIAN__ | |
#define __ORDER_LITTLE_ENDIAN__ 1234 | |
#endif | |
#ifndef __BYTE_ORDER__ | |
#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__ | |
#endif | |
#endif | |
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ | |
#define ENDIANIO_LITTLE_ENDIAN 1 | |
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ | |
#define ENDIANIO_BIG_ENDIAN 1 | |
#else | |
#error "Byte order is neither little endian nor big endian. Do not know how to proceed." | |
#endif | |
#if defined(__clang__) || defined(__GNUG__) | |
#define FORCE_INLINE __attribute__((always_inline)) inline | |
#elif defined(_MSC_VER) | |
#define FORCE_INLINE __forceinline | |
#else | |
#define FORCE_INLINE inline | |
#endif | |
#ifdef __GNUG__ | |
#define ATTR_CONST __attribute__((const)) | |
#define ATTR_PURE __attribute__((pure)) | |
#define CONSTEXPR constexpr | |
#else | |
#define ATTR_CONST | |
#define ATTR_PURE | |
#define CONSTEXPR | |
#endif | |
#ifdef __INTEL_COMPILER | |
#define assume(x) do {bool const valid = (x); __assume(valid);} while (false) | |
#elif defined(__GNUG__) | |
#define assume(x) if (!(x)) __builtin_unreachable() | |
#elif defined(_MSC_VER) | |
#define assume(x) __assume((x)) | |
#else | |
#define assume(x) | |
#endif | |
#ifdef _LIBCPP_VERSION | |
namespace std { | |
using streamsize = ptrdiff_t; | |
} | |
#elif defined(_MSC_VER) | |
#include <stdlib.h> | |
#pragma intrinsic(_byteswap_ushort) | |
#pragma intrinsic(_byteswap_ulong) | |
#pragma intrinsic(_byteswap_uint64) | |
#elif defined(__INTEL_COMPILER) | |
#include <byteswap.h> | |
#endif | |
// Note: Opening namespace std and adding stuff is undefined behavior. | |
// This works with MSVC (MS-STL), g++ (libstdc++), clang (libc++), | |
// and icc (using any of these libraries). | |
// Doing this as a compatibility hack with C++17 and newer; when moving | |
// to a new standard, I can just remove portions of this. | |
//NOLINTNEXTLINE(cert-dcl58-cpp) | |
namespace std { | |
// MS-STL is nonconforming, and has all c++17 stuff available for | |
// pre-c++17 without any of the feature macros. | |
#if (defined(__GLIBCXX__) || defined(_LIBCPP_VERSION)) && __cplusplus < 201703L | |
// _v traits (ported from C++17). | |
//NOLINTNEXTLINE(cppcoreguidelines-macro-usage) | |
#define DEFINE_TRAIT_VARIABLE(trait) template <typename... T> constexpr bool trait ## _v = std::trait<T...>::value | |
DEFINE_TRAIT_VARIABLE(is_integral); | |
DEFINE_TRAIT_VARIABLE(is_pointer); | |
DEFINE_TRAIT_VARIABLE(is_same); | |
DEFINE_TRAIT_VARIABLE(is_signed); | |
DEFINE_TRAIT_VARIABLE(is_unsigned); | |
#undef DEFINE_TRAIT_VARIABLE | |
#if !defined(__cpp_lib_void_t) || __cpp_lib_void_t < 201411L | |
// void_t (ported from C++17). | |
// More complicated than needed due to CWG issue 1558. | |
namespace __detail { | |
template <typename... Ts> | |
struct make_void { | |
using type = void; | |
}; | |
} // namespace __detail | |
template <typename... Ts> | |
using void_t = typename __detail::make_void<Ts...>::type; | |
#endif | |
// bool_constant (ported from C++17). | |
template <bool B> | |
using bool_constant = std::integral_constant<bool, B>; | |
// Negation (ported from C++17). | |
template <typename B> | |
struct negation : std::integral_constant<bool, !B::value> {}; | |
template <typename B> | |
constexpr bool negation_v = negation<B>::value; | |
// Conjunction (ported from C++17). | |
template <typename...> | |
struct conjunction : std::true_type {}; | |
template <typename B1> | |
struct conjunction<B1> : B1 {}; | |
template <typename B1, typename... Bn> | |
struct conjunction<B1, Bn...> : std::conditional_t<B1::value, conjunction<Bn...>, B1> {}; | |
template <typename... B> | |
constexpr bool conjunction_v = conjunction<B...>::value; | |
// Disjunction (ported from C++17). | |
template <typename...> | |
struct disjunction : std::false_type {}; | |
template <typename B1> | |
struct disjunction<B1> : B1 {}; | |
template <typename B1, typename... Bn> | |
struct disjunction<B1, Bn...> : std::conditional_t<B1::value, B1, disjunction<Bn...>> {}; | |
template <typename... B> | |
constexpr bool disjunction_v = disjunction<B...>::value; | |
#endif | |
// Type identity (ported from C++20). | |
template <typename T> | |
struct type_identity { | |
using type = T; | |
}; | |
template <typename T> | |
using type_identity_t = typename type_identity<T>::type; | |
// Utility to convert "fancy pointer" to pointer (ported from C++20). | |
template <typename T> | |
FORCE_INLINE ATTR_CONST constexpr auto to_address(T* in) noexcept { | |
return in; | |
} | |
template <typename Iter> | |
FORCE_INLINE ATTR_PURE constexpr auto to_address(Iter in) { | |
return to_address(in.operator->()); | |
} | |
// assume_aligned (ported from C++20). | |
template <size_t N, typename T> | |
FORCE_INLINE ATTR_CONST constexpr auto assume_aligned(T* ptr) noexcept { | |
#if defined(__clang__) || defined(__GNUG__) | |
//NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg) | |
return static_cast<T*>(__builtin_assume_aligned(ptr, N)); | |
#elif defined(_MSC_VER) | |
if ((reinterpret_cast<std::uintptr_t>(ptr) % N) == 0) { | |
return ptr; | |
} else { | |
assume(false); | |
return nullptr; | |
} | |
#else | |
return ptr; | |
#endif | |
} | |
// is_detected and related (ported from Library Fundamentals v2). | |
namespace __detail { | |
template <typename Default, typename AlwaysVoid, template <typename...> class Op, typename... Args> | |
struct detector { | |
using value_t = std::false_type; | |
using type = Default; | |
}; | |
template <typename Default, template <typename...> class Op, typename... Args> | |
struct detector<Default, void_t<Op<Args...>>, Op, Args...> { | |
using value_t = std::true_type; | |
using type = Op<Args...>; | |
}; | |
struct nonesuch final { | |
nonesuch(nonesuch const&) = delete; | |
nonesuch(nonesuch&&) = delete; | |
nonesuch() = delete; | |
~nonesuch() = delete; | |
auto operator=(nonesuch const&) -> nonesuch& = delete; | |
auto operator=(nonesuch&&) -> nonesuch& = delete; | |
}; | |
} // namespace __detail | |
template <template <typename...> class Op, typename... Args> | |
using is_detected = typename __detail::detector<__detail::nonesuch, void, Op, Args...>::value_t; | |
template <template <typename...> class Op, typename... Args > | |
constexpr bool is_detected_v = is_detected<Op, Args...>::value; | |
template <template <typename...> class Op, typename... Args> | |
using detected_t = typename __detail::detector<__detail::nonesuch, void, Op, Args...>::type; | |
template <typename Default, template <typename...> class Op, typename... Args> | |
using detected_or = __detail::detector<Default, void, Op, Args...>; | |
template <typename Default, template <typename...> class Op, typename... Args > | |
using detected_or_t = typename __detail::detector<Default, void, Op, Args...>::type; | |
template <typename Expected, template <typename...> class Op, typename... Args> | |
using is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>; | |
template <typename Expected, template <typename...> class Op, typename... Args> | |
constexpr bool is_detected_exact_v = is_detected_exact<Expected, Op, Args...>::value; | |
template <typename To, template <typename...> class Op, typename... Args> | |
using is_detected_convertible = std::is_convertible<detected_t<Op, Args...>, To>; | |
template <typename To, template <typename...> class Op, typename... Args> | |
constexpr bool is_detected_convertible_v = is_detected_convertible<To, Op, Args...>::value; | |
} // namespace std | |
namespace detail { | |
// Meta-programming stuff. | |
// Utility for finding if a type appears in a list of types. | |
template <typename Value, typename...> | |
struct is_any_of : std::false_type {}; | |
template <typename Value, typename B1, typename... Bn> | |
struct is_any_of<Value, B1, Bn...> : std::bool_constant< | |
std::is_same_v<Value, B1> || is_any_of<Value, Bn...>::value> {}; | |
template <typename Value, typename... Bs> | |
constexpr bool is_any_of_v = is_any_of<Value, Bs...>::value; | |
// Concepts-like syntax. Based on code by Isabella Muerte. | |
template <bool... Bs> | |
constexpr bool require = std::conjunction_v<std::bool_constant<Bs>...>; | |
template <bool... Bs> | |
constexpr bool either = std::disjunction_v<std::bool_constant<Bs>...>; | |
template <bool... Bs> | |
constexpr bool disallow = std::negation_v<std::disjunction<std::bool_constant<Bs>...>>; | |
template <template <typename...> class Op, typename... Args> | |
constexpr bool exists = std::is_detected_v<Op, Args...>; | |
template <typename To, template <typename...> class Op, typename... Args> | |
constexpr bool converts_to = std::is_detected_convertible_v<To, Op, Args...>; | |
template <typename Exact, template <typename...> class Op, typename... Args> | |
constexpr bool identical_to = std::is_detected_exact_v<Exact, Op, Args...>; | |
namespace functions { | |
template <typename T> | |
using push_back = decltype(std::declval<T>().push_back(std::declval<typename T::value_type>())); | |
template <typename T> | |
using size = decltype(std::declval<T>().size()); | |
template <typename T> | |
using resize = decltype(std::declval<T>().resize(std::declval<typename T::size_type>())); | |
template <typename T> | |
using data = decltype(std::declval<T>().data()); | |
template <typename T> | |
using sgetn = decltype(std::declval<T>().sgetn(std::declval<char*>(), std::declval<std::streamsize>())); | |
template <typename T> | |
using sputn = decltype(std::declval<T>().sputn(std::declval<char const*>(), std::declval<std::streamsize>())); | |
template <typename T> | |
using read = decltype(std::declval<T>().read(std::declval<char*>(), std::declval<std::streamsize>())); | |
template <typename T> | |
using write = decltype(std::declval<T>().write(std::declval<char const*>(), std::declval<std::streamsize>())); | |
template <typename T> | |
using begin = decltype(std::declval<T>().begin()); | |
template <typename T> | |
using cbegin = decltype(std::declval<T>().cbegin()); | |
template <typename T> | |
using end = decltype(std::declval<T>().end()); | |
template <typename T> | |
using cend = decltype(std::declval<T>().cend()); | |
template <typename T> | |
using empty = decltype(std::declval<T>().empty()); | |
} // namespace functions | |
namespace aliases { | |
//NOLINTNEXTLINE(bugprone-macro-parentheses,cppcoreguidelines-macro-usage) | |
#define MPL_DEFINE_HAS_ALIAS(alias_name) template <typename T> using alias_name = typename T::alias_name; | |
MPL_DEFINE_HAS_ALIAS(char_type) | |
MPL_DEFINE_HAS_ALIAS(value_type) | |
MPL_DEFINE_HAS_ALIAS(iterator) | |
MPL_DEFINE_HAS_ALIAS(iterator_type) | |
MPL_DEFINE_HAS_ALIAS(const_iterator) | |
MPL_DEFINE_HAS_ALIAS(size_type) | |
MPL_DEFINE_HAS_ALIAS(difference_type) | |
MPL_DEFINE_HAS_ALIAS(reference) | |
MPL_DEFINE_HAS_ALIAS(const_reference) | |
MPL_DEFINE_HAS_ALIAS(iterator_category) | |
MPL_DEFINE_HAS_ALIAS(container_type) | |
MPL_DEFINE_HAS_ALIAS(pointer) | |
MPL_DEFINE_HAS_ALIAS(const_pointer) | |
MPL_DEFINE_HAS_ALIAS(streambuf_type) | |
MPL_DEFINE_HAS_ALIAS(istream_type) | |
MPL_DEFINE_HAS_ALIAS(ostream_type) | |
#undef MPL_DEFINE_HAS_ALIAS | |
} // namespace aliases | |
namespace traits { | |
template <typename T> | |
using iterator_traits = typename std::iterator_traits<T>; | |
} // namespace traits | |
namespace ops { | |
template <class T, class U> | |
using equal_to = decltype(std::declval<T>() == std::declval<U>()); | |
template <class T, class U> | |
using not_equal = decltype(std::declval<T>() != std::declval<U>()); | |
template <class T, class U> | |
using less = decltype(std::declval<T>() < std::declval<U>()); | |
template <class T> | |
using dereference = decltype(*std::declval<T>()); | |
template <class T> | |
using arrow = decltype(std::declval<T>().operator->()); | |
template <class T> | |
using postfix_increment = decltype(std::declval<T>()++); | |
template <class T> | |
using prefix_increment = decltype(++std::declval<T>()); | |
} // namespace ops | |
namespace adl { | |
using std::swap; | |
template <class T, class U=T> | |
using swap_with = decltype(swap(std::declval<T>(), std::declval<U>())); | |
} // namespace adl | |
namespace concepts { | |
template <class T> | |
constexpr bool DefaultConstructible = std::is_default_constructible<T>::value; | |
template <class T> | |
constexpr bool CopyConstructible = std::is_copy_constructible<T>::value; | |
template <class T> | |
constexpr bool CopyAssignable = std::is_copy_assignable<T>::value; | |
template <class T> | |
constexpr bool Destructible = std::is_destructible<T>::value; | |
template <class T, class U = T> | |
constexpr bool EqualityComparable = require< | |
converts_to<bool, ops::equal_to, T, U>, | |
converts_to<bool, ops::not_equal, T, U> | |
>; | |
template <class T, class U> | |
constexpr bool SwappableWith = exists<adl::swap_with, T, U>; | |
template <class T> | |
constexpr bool Swappable = SwappableWith<T&, T&>; | |
template <class T> | |
constexpr bool Pointer = std::is_pointer<T>::value; | |
template <typename T> | |
constexpr bool Container = require< | |
exists<aliases::value_type, T>, | |
exists<aliases::reference, T>, | |
exists<aliases::const_reference, T>, | |
exists<aliases::iterator, T>, | |
exists<aliases::const_iterator, T>, | |
exists<aliases::difference_type, T>, | |
exists<aliases::size_type, T>, | |
concepts::DefaultConstructible<T>, | |
concepts::CopyConstructible<T>, | |
concepts::CopyAssignable<T>, | |
concepts::Destructible<T>, | |
concepts::EqualityComparable<T>, | |
concepts::Swappable<T>, | |
exists<functions::size, T>, | |
exists<functions::empty, T>, | |
either< | |
identical_to<std::detected_t<aliases::iterator, T>, functions::begin, T>, | |
identical_to<std::detected_t<aliases::const_iterator, T>, functions::begin, T> | |
>, | |
either< | |
identical_to<std::detected_t<aliases::iterator, T>, functions::end, T>, | |
identical_to<std::detected_t<aliases::const_iterator, T>, functions::end, T> | |
>, | |
identical_to<std::detected_t<aliases::const_iterator, T>, functions::cbegin, T>, | |
identical_to<std::detected_t<aliases::const_iterator, T>, functions::cend, T> | |
>; | |
template <class T> | |
constexpr bool Iterator = require< | |
CopyConstructible<T>, | |
CopyAssignable<T>, | |
Destructible<T>, | |
Swappable<T>, | |
exists<ops::postfix_increment, T>, | |
exists<ops::prefix_increment, T>, | |
exists<ops::dereference, T> | |
>; | |
} // namespace concepts | |
template <template <typename...> class Op, typename... Args> | |
constexpr bool is_character_type_v = is_any_of_v< | |
std::remove_cv_t<std::detected_t<Op, Args...>>, | |
#if __cplusplus >= 201703L | |
std::byte, | |
#endif | |
char, unsigned char | |
>; | |
template <typename T> | |
struct is_pointer_like : std::bool_constant< | |
either< | |
require< | |
concepts::Pointer<T>, | |
is_character_type_v<aliases::value_type, std::detected_t<traits::iterator_traits, T>> | |
>, | |
require< | |
concepts::Iterator<T>, | |
either< | |
// For (back_|front_)?insert_iterator: | |
require< | |
converts_to< | |
std::output_iterator_tag, | |
aliases::iterator_category, | |
std::detected_t<traits::iterator_traits, T> | |
>, | |
is_character_type_v<aliases::value_type, std::detected_t<aliases::container_type, T>> | |
>, | |
// For all other iterators: | |
require< | |
converts_to< | |
std::forward_iterator_tag, | |
aliases::iterator_category, | |
std::detected_t<traits::iterator_traits, T> | |
>, | |
is_character_type_v<aliases::value_type, std::detected_t<traits::iterator_traits, T>> | |
> | |
> | |
> | |
> | |
> {}; | |
template <typename T> | |
struct is_pointer_like<T&> : is_pointer_like<T> {}; | |
template <typename T> | |
constexpr bool is_pointer_like_v = is_pointer_like<T>::value; | |
template <typename T> | |
struct is_contiguous_container : std::bool_constant< | |
require< | |
concepts::Container<T>, | |
exists<functions::resize, T>, | |
either< | |
identical_to<std::detected_t<functions::data, T>, aliases::pointer, T>, | |
identical_to<std::detected_t<functions::data, T>, aliases::const_pointer, T> | |
>, | |
is_character_type_v<aliases::value_type, T> | |
> | |
> {}; | |
template <typename T> | |
struct is_contiguous_container<T&> : is_contiguous_container<T> {}; | |
template <typename T> | |
struct is_push_back_container : std::bool_constant< | |
require< | |
concepts::Container<T>, | |
exists<functions::push_back, T>, | |
disallow< | |
exists<functions::data, T> | |
>, | |
is_character_type_v<aliases::value_type, T> | |
> | |
> {}; | |
template <typename T> | |
struct is_push_back_container<T&> : is_push_back_container<T> {}; | |
template <template <typename...> class Op, typename... Args> | |
struct pointer_or_char : std::type_identity< | |
std::conditional_t< | |
std::is_pointer_v<std::detected_t<Op, Args...>>, | |
std::detected_t<Op, Args...>, | |
char | |
> | |
> {}; | |
template <template <typename...> class Op, typename... Args> | |
using pointer_or_char_t = typename pointer_or_char<Op, Args...>::type; | |
// Note: fails for stupid stuff like std::reverse_iterator<std::reverse_iterator<T>>. | |
// This failure is intentional. | |
template <typename T> | |
struct is_reverse_iterator : std::false_type {}; | |
template <typename T> | |
struct is_reverse_iterator<std::reverse_iterator<T>> : std::true_type {}; | |
template <typename T> | |
struct is_reverse_iterator<const T> : is_reverse_iterator<T> {}; | |
template <typename T> | |
struct is_reverse_iterator<T&> : is_reverse_iterator<T> {}; | |
template <typename T> | |
struct is_really_reverse_iterator : std::false_type {}; | |
template <typename T> | |
struct is_really_reverse_iterator<std::reverse_iterator<T>> : std::bool_constant< | |
!is_really_reverse_iterator<T>::value | |
> {}; | |
template <typename T> | |
struct is_really_reverse_iterator<std::move_iterator<T>> : std::bool_constant< | |
is_really_reverse_iterator<T>::value | |
> {}; | |
template <typename T> | |
struct is_really_reverse_iterator<const T> : is_really_reverse_iterator<T> {}; | |
template <typename T> | |
struct is_really_reverse_iterator<T&> : is_really_reverse_iterator<T> {}; | |
// Probably unportable assumption: if the iterator is | |
// the size of a pointer, the only thing it can hold | |
// is a pointer. So it cannot be a deque iterator. | |
// This works with MSVC (MS-STL), g++ (libstdc++), | |
// clang (libc++), and icc (using any of these libraries). | |
template <typename Iter> | |
struct is_maybe_contiguous_iterator : std::bool_constant< | |
require< | |
converts_to< | |
std::random_access_iterator_tag, | |
aliases::iterator_category, | |
std::detected_t<traits::iterator_traits, Iter> | |
>, | |
disallow< | |
std::is_detected_exact_v<void, aliases::value_type, std::detected_t<traits::iterator_traits, Iter>> | |
>, | |
sizeof(Iter) == sizeof(pointer_or_char_t<aliases::pointer, std::detected_t<traits::iterator_traits, Iter>>) | |
> | |
> {}; | |
template <typename T> | |
struct is_maybe_contiguous_iterator<const T> : is_maybe_contiguous_iterator<T> {}; | |
template <typename T> | |
struct is_maybe_contiguous_iterator<T&> : is_maybe_contiguous_iterator<T> {}; | |
template <typename Iter, bool> | |
struct is_contiguous_iterator_impl : std::bool_constant< | |
is_maybe_contiguous_iterator<Iter>::value | |
> {}; | |
template <typename Iter> | |
struct is_contiguous_iterator_impl<Iter, true> : std::bool_constant< | |
is_contiguous_iterator_impl< | |
std::detected_t< | |
aliases::iterator_type, | |
Iter | |
>, | |
is_reverse_iterator< | |
std::detected_t< | |
aliases::iterator_type, | |
Iter | |
> | |
>::value | |
>::value | |
> {}; | |
template <typename Iter> | |
struct is_contiguous_iterator : std::bool_constant< | |
is_contiguous_iterator_impl<Iter, is_reverse_iterator<Iter>::value>::value | |
> {}; | |
template <typename T> | |
struct is_contiguous_iterator<const T> : is_contiguous_iterator<T> {}; | |
template <typename T> | |
struct is_contiguous_iterator<T&> : is_contiguous_iterator<T> {}; | |
// Robust SFINAE idiom by Jonathan Boccara | |
// https://www.fluentcpp.com/2019/08/23/how-to-make-sfinae-pretty-and-robust/ | |
template <typename T> | |
using has_read_function_t = std::enable_if_t<exists<functions::read, T>, bool>; | |
template <typename T> | |
using has_sgetn_function_t = std::enable_if_t<exists<functions::sgetn, T>, bool>; | |
template <typename T> | |
using has_write_function_t = std::enable_if_t<exists<functions::write, T>, bool>; | |
template <typename T> | |
using has_sputn_function_t = std::enable_if_t<exists<functions::sputn, T>, bool>; | |
template <typename T> | |
using is_contiguous_container_t = std::enable_if_t<is_contiguous_container<T>::value, bool>; | |
template <typename T> | |
using is_push_back_container_t = std::enable_if_t<is_push_back_container<T>::value, bool>; | |
template <typename T> | |
using is_pointer_like_t = std::enable_if_t<is_pointer_like_v<T>, bool>; | |
template <typename T> | |
using is_unsigned_integer_t = std::enable_if_t< | |
require< | |
std::is_integral_v<T>, | |
std::is_unsigned_v<T>, | |
!std::is_same_v<T, bool> | |
>, bool>; | |
template <typename T> | |
using is_signed_integer_t = std::enable_if_t< | |
require< | |
std::is_integral_v<T>, | |
std::is_signed_v<T> | |
>, bool>; | |
// base case: just fail | |
template <size_t Size, typename... > | |
struct select_unsigned; | |
// recursive case: check using numeric_limits | |
template <size_t Size, typename T, typename... Ts> | |
struct select_unsigned<Size, T, Ts...> : std::conditional_t< | |
Size == sizeof(T), std::type_identity<T>, select_unsigned<Size, Ts...>> {}; | |
template <uint64_t Size> | |
using select_unsigned_t = typename select_unsigned<Size, uint8_t, uint16_t, uint32_t, uint64_t>::type; | |
template <typename T, typename Iter> | |
FORCE_INLINE ATTR_PURE constexpr auto to_aligned_address(Iter it) { | |
return std::assume_aligned<sizeof(T)>(std::to_address(it)); | |
} | |
template <typename T, typename Iter> | |
FORCE_INLINE ATTR_PURE constexpr auto to_unaligned_address(Iter it) { | |
#if defined(__GNUG__) || !defined(_MSC_VER) | |
return std::to_address(it); | |
#else | |
_unaligned auto ptr{std::to_address(it)}; | |
return ptr; | |
#endif | |
} | |
FORCE_INLINE ATTR_CONST CONSTEXPR auto bswap(uint8_t val) noexcept -> uint8_t { | |
return val; | |
} | |
FORCE_INLINE ATTR_CONST CONSTEXPR auto bswap(uint16_t val) noexcept -> uint16_t { | |
#if defined(__GNUG__) | |
#ifdef __INTEL_COMPILER | |
if (__builtin_constant_p(val)) { | |
return __bswap_constant_16(val); | |
} | |
#endif | |
return __builtin_bswap16(val); | |
#elif defined(_MSC_VER) | |
return _byteswap_ushort(val); | |
#else | |
return ((val & 0xffu) << 8) | ((val >> 8) & 0xffu); | |
#endif | |
} | |
FORCE_INLINE ATTR_CONST CONSTEXPR auto bswap(uint32_t val) noexcept -> uint32_t { | |
#if defined(__GNUG__) | |
#ifdef __INTEL_COMPILER | |
if (__builtin_constant_p(val)) { | |
return __bswap_constant_32(val); | |
} | |
#endif | |
return __builtin_bswap32(val); | |
#elif defined(_MSC_VER) | |
return _byteswap_ulong(val); | |
#else | |
val = ((val & 0xffffu) << 16) | ((val >> 16) & 0xffffu); | |
return ((val & 0xff00ffu) << 8) | ((val >> 8) & 0xff00ffu); | |
#endif | |
} | |
FORCE_INLINE ATTR_CONST CONSTEXPR auto bswap(uint64_t val) noexcept -> uint64_t { | |
#if defined(__GNUG__) | |
#ifdef __INTEL_COMPILER | |
if (__builtin_constant_p(val)) { | |
return __bswap_constant_64(val); | |
} | |
#endif | |
return __builtin_bswap64(val); | |
#elif defined(_MSC_VER) | |
return _byteswap_uint64(val); | |
#else | |
val = ((val & 0xffffffffull) << 32) | ((val >> 32) & 0xffffffffull); | |
val = ((val & 0xffff0000ffffull) << 16) | ((val >> 16) & 0xffff0000ffffull); | |
return ((val & 0xff00ff00ff00ffull) << 8) | ((val >> 8) & 0xff00ff00ff00ffull); | |
#endif | |
} | |
namespace impl { | |
template <typename T> | |
struct ByteIdentity { | |
FORCE_INLINE ATTR_CONST static constexpr auto Get(T val) noexcept -> T { | |
return val; | |
} | |
}; | |
template <typename T> | |
struct ByteReverse { | |
FORCE_INLINE ATTR_CONST static constexpr auto Get(T val) noexcept -> T { | |
return bswap(val); | |
} | |
}; | |
template <bool bigendian, typename T> | |
class DoEndianByteIO { | |
FORCE_INLINE ATTR_CONST static constexpr auto calcShift(size_t N) -> size_t { | |
if (bigendian) { | |
return (sizeof(T) - 1 - N) * 8; | |
} | |
return (N * 8); | |
} | |
#if __cplusplus < 201703L | |
using expander = int[]; | |
#endif | |
public: | |
template <typename Iter, size_t... Is> | |
FORCE_INLINE static constexpr auto Read(Iter in, std::index_sequence<Is...> /*seq*/) { | |
T val{}; | |
auto getByte = [&](size_t shift) { | |
auto cc = static_cast<T>(*in) << shift; | |
++in; | |
val |= cc; | |
}; | |
#if __cplusplus >= 201703L | |
static_cast<void>((getByte(calcShift(Is)), ...)); | |
#else | |
static_cast<void>(expander{(getByte(calcShift(Is)), 0)...}); | |
#endif | |
return std::make_pair(in, val); | |
} | |
template <typename Iter, size_t... Is> | |
FORCE_INLINE static constexpr auto Write(Iter out, T val, std::index_sequence<Is...> /*seq*/) { | |
using uint = std::conditional_t< | |
exists<aliases::value_type, std::detected_t<aliases::container_type, Iter>>, | |
std::detected_t<aliases::value_type, std::detected_t<aliases::container_type, Iter>>, | |
std::detected_or_t<char, aliases::value_type, std::detected_t<traits::iterator_traits, Iter>>>; | |
auto putByte = [&](size_t shift) { | |
*out = static_cast<uint>(val >> shift); | |
++out; | |
}; | |
#if __cplusplus >= 201703L | |
static_cast<void>((putByte(calcShift(Is)), ...)); | |
#else | |
static_cast<void>(expander{(putByte(calcShift(Is)), 0)...}); | |
#endif | |
return out; | |
} | |
}; | |
} // namespace impl | |
template <typename T> | |
using BigEndianByteIO = impl::DoEndianByteIO<true, T>; | |
template <typename T> | |
using LittleEndianByteIO = impl::DoEndianByteIO<false, T>; | |
template <template <typename> class Convert, | |
template <typename> class Preserve, | |
template <typename> class ByteIO> | |
struct EndianHandlerBase { | |
template <typename T> | |
FORCE_INLINE ATTR_CONST constexpr auto convert(T val) const noexcept -> T { | |
return Convert<T>::Get(val); | |
} | |
template <typename T> | |
FORCE_INLINE ATTR_CONST constexpr auto keep(T val) const noexcept -> T { | |
return Preserve<T>::Get(val); | |
} | |
template <typename T, typename Iter> | |
FORCE_INLINE constexpr auto read(Iter&& in) const -> T { | |
auto ret = ByteIO<T>::Read(std::forward<Iter>(in), std::make_index_sequence<sizeof(T)>()); | |
in = ret.first; | |
return ret.second; | |
} | |
template <typename T, typename Iter> | |
FORCE_INLINE constexpr void write(Iter&& out, T val) const { | |
out = ByteIO<T>::Write(std::forward<Iter>(out), val, std::make_index_sequence<sizeof(T)>()); | |
} | |
}; | |
#ifdef ENDIANIO_LITTLE_ENDIAN | |
using EndianIdentity = EndianHandlerBase<impl::ByteIdentity, impl::ByteReverse , LittleEndianByteIO>; | |
using EndianReverse = EndianHandlerBase<impl::ByteReverse , impl::ByteIdentity, BigEndianByteIO >; | |
#elif defined(ENDIANIO_BIG_ENDIAN) | |
using EndianIdentity = EndianHandlerBase<impl::ByteIdentity, impl::ByteReverse , BigEndianByteIO >; | |
using EndianReverse = EndianHandlerBase<impl::ByteReverse , impl::ByteIdentity, LittleEndianByteIO>; | |
#endif | |
struct EndianBaseImpl { | |
private: | |
// GCC and clang generate optimal code with the other version. | |
// Need this version for MSVC and ICC. | |
template <typename T, typename EndianHandler, typename Iter> | |
FORCE_INLINE static auto ReadInternal(Iter&& in, EndianHandler endian, std::true_type /*tag*/) -> T { | |
auto ptr{to_unaligned_address<T>(in)}; | |
if (is_really_reverse_iterator<Iter>::value) { | |
std::advance(ptr, -ptrdiff_t(sizeof(T)-1)); | |
} | |
T val; | |
std::memcpy(&val, ptr, sizeof(T)); | |
if (is_really_reverse_iterator<Iter>::value) { | |
val = endian.keep(val); | |
} else { | |
val = endian.convert(val); | |
} | |
std::advance(in, sizeof(T)); | |
return val; | |
} | |
template <typename T, typename EndianHandler, typename Iter> | |
FORCE_INLINE static auto ReadInternal(Iter&& in, EndianHandler endian, std::false_type /*tag*/) -> T { | |
return endian.template read<T>(std::forward<Iter>(in)); | |
} | |
// GCC generates optimal code with the other version. | |
// Need this version for clang, MSVC, and ICC. | |
template <typename T, typename EndianHandler, typename Iter> | |
FORCE_INLINE static void WriteInternal(Iter&& out, EndianHandler endian, T val, std::true_type /*tag*/) { | |
auto ptr{to_unaligned_address<T>(out)}; | |
if (is_really_reverse_iterator<Iter>::value) { | |
std::advance(ptr, -ptrdiff_t(sizeof(T)-1)); | |
val = endian.keep(val); | |
} else { | |
val = endian.convert(val); | |
} | |
std::memcpy(ptr, &val, sizeof(T)); | |
std::advance(out, sizeof(T)); | |
} | |
template <typename T, typename EndianHandler, typename Iter> | |
FORCE_INLINE static void WriteInternal(Iter&& out, EndianHandler endian, T val, std::false_type /*tag*/) { | |
endian.write(std::forward<Iter>(out), val); | |
} | |
public: | |
template <typename T, typename EndianHandler, typename Stream, has_read_function_t<Stream> = true> | |
FORCE_INLINE static auto Read(Stream& in, EndianHandler endian) { | |
alignas(alignof(T)) typename Stream::char_type buffer[sizeof(T)]; | |
in.read(std::begin(buffer), sizeof(T)); | |
return Read<T>(std::begin(buffer), endian); | |
} | |
template <typename T, typename EndianHandler, typename Buf, has_sgetn_function_t<Buf> = true> | |
FORCE_INLINE static auto Read(Buf& in, EndianHandler endian) { | |
alignas(alignof(T)) typename Buf::char_type buffer[sizeof(T)]; | |
in.sgetn(std::begin(buffer), sizeof(T)); | |
return Read<T>(std::begin(buffer), endian); | |
} | |
template <typename T, typename EndianHandler, typename Iter, is_pointer_like_t<Iter> = true> | |
FORCE_INLINE static auto Read(Iter&& in, EndianHandler endian) { | |
return ReadInternal<T>(std::forward<Iter>(in), endian, is_contiguous_iterator<Iter>()); | |
} | |
template <typename T, typename EndianHandler, typename Stream, has_write_function_t<Stream> = true> | |
FORCE_INLINE static auto Write(Stream& out, EndianHandler endian, T val) { | |
alignas(alignof(T)) typename Stream::char_type buffer[sizeof(T)]; | |
Write(std::begin(buffer), endian, val); | |
out.write(std::cbegin(buffer), sizeof(T)); | |
} | |
template <typename T, typename EndianHandler, typename Buf, has_sputn_function_t<Buf> = true> | |
FORCE_INLINE static auto Write(Buf& out, EndianHandler endian, T val) { | |
alignas(alignof(T)) typename Buf::char_type buffer[sizeof(T)]; | |
Write(std::begin(buffer), endian, val); | |
out.sputn(std::cbegin(buffer), sizeof(T)); | |
} | |
template <typename T, typename EndianHandler, typename Cont, is_contiguous_container_t<Cont> = true> | |
FORCE_INLINE static auto Write(Cont& out, EndianHandler endian, T val) { | |
auto sz = out.size(); | |
out.resize(sz + sizeof(T)); | |
Write(std::addressof(out[sz]), endian, val); | |
} | |
template <typename T, typename EndianHandler, typename Cont, is_push_back_container_t<Cont> = true> | |
FORCE_INLINE static auto Write(Cont& out, EndianHandler endian, T val) { | |
Write(std::back_inserter(out), endian, val); | |
} | |
template <typename T, typename EndianHandler, typename Iter, is_pointer_like_t<Iter> = true> | |
FORCE_INLINE static auto Write(Iter&& out, EndianHandler endian, T val) { | |
WriteInternal(std::forward<Iter>(out), endian, val, is_contiguous_iterator<Iter>()); | |
} | |
}; | |
#undef assume | |
template <size_t Size> | |
using uintN_t = select_unsigned_t<Size>; | |
template <typename EndianHandler> | |
struct EndianBase { | |
template <typename Src> | |
FORCE_INLINE static auto Read1(Src&& in) -> uint8_t { | |
return EndianBaseImpl::Read<uint8_t>(std::forward<Src>(in), EndianHandler{}); | |
} | |
template <typename Src> | |
FORCE_INLINE static auto Read2(Src&& in) -> uint16_t { | |
return EndianBaseImpl::Read<uint16_t>(std::forward<Src>(in), EndianHandler{}); | |
} | |
template <typename Src> | |
FORCE_INLINE static auto Read4(Src&& in) -> uint32_t { | |
return EndianBaseImpl::Read<uint32_t>(std::forward<Src>(in), EndianHandler{}); | |
} | |
template <typename Src> | |
FORCE_INLINE static auto Read8(Src&& in) -> uint64_t { | |
return EndianBaseImpl::Read<uint64_t>(std::forward<Src>(in), EndianHandler{}); | |
} | |
template <size_t Size, typename Src> | |
FORCE_INLINE static auto ReadN(Src&& in) -> uintN_t<Size> { | |
return EndianBaseImpl::Read<uintN_t<Size>>(std::forward<Src>(in), EndianHandler{}); | |
} | |
template <typename T, typename Src, is_unsigned_integer_t<T> = true> | |
FORCE_INLINE static auto Read(Src&& in) { | |
return EndianBaseImpl::Read<T>(std::forward<Src>(in), EndianHandler{}); | |
} | |
template <typename T, typename Src, is_signed_integer_t<T> = true> | |
FORCE_INLINE static auto Read(Src&& in) { | |
using uint_t = typename std::make_unsigned<T>::type; | |
uint_t valu = EndianBaseImpl::Read<uint_t>(std::forward<Src>(in), EndianHandler{}); | |
T val; | |
std::memcpy(&val, &valu, sizeof(T)); | |
return val; | |
} | |
template <typename Dst> | |
FORCE_INLINE static void Write1(Dst&& out, uint8_t val) { | |
EndianBaseImpl::Write(std::forward<Dst>(out), EndianHandler{}, val); | |
} | |
template <typename Dst> | |
FORCE_INLINE static void Write1(Dst&& out, int8_t val) { | |
EndianBaseImpl::Write(std::forward<Dst>(out), EndianHandler{}, val); | |
} | |
template <typename Dst> | |
FORCE_INLINE static void Write2(Dst&& out, uint16_t val) { | |
EndianBaseImpl::Write(std::forward<Dst>(out), EndianHandler{}, val); | |
} | |
template <typename Dst> | |
FORCE_INLINE static void Write2(Dst&& out, int16_t val) { | |
EndianBaseImpl::Write(std::forward<Dst>(out), EndianHandler{}, val); | |
} | |
template <typename Dst> | |
FORCE_INLINE static void Write4(Dst&& out, uint32_t val) { | |
EndianBaseImpl::Write(std::forward<Dst>(out), EndianHandler{}, val); | |
} | |
template <typename Dst> | |
FORCE_INLINE static void Write4(Dst&& out, int32_t val) { | |
EndianBaseImpl::Write(std::forward<Dst>(out), EndianHandler{}, val); | |
} | |
template <typename Dst> | |
FORCE_INLINE static void Write8(Dst&& out, uint64_t val) { | |
EndianBaseImpl::Write(std::forward<Dst>(out), EndianHandler{}, val); | |
} | |
template <typename Dst> | |
FORCE_INLINE static void Write8(Dst&& out, int64_t val) { | |
EndianBaseImpl::Write(std::forward<Dst>(out), EndianHandler{}, val); | |
} | |
template <size_t Size, typename Dst> | |
FORCE_INLINE static void WriteN(Dst&& out, uintN_t<Size> val) { | |
EndianBaseImpl::Write(std::forward<Dst>(out), EndianHandler{}, val); | |
} | |
template <typename T, typename Dst, is_unsigned_integer_t<T> = true> | |
FORCE_INLINE static auto Write(Dst&& out, T val) { | |
EndianBaseImpl::Write(std::forward<Dst>(out), EndianHandler{}, val); | |
} | |
template <typename T, typename Dst, is_signed_integer_t<T> = true> | |
FORCE_INLINE static auto Write(Dst&& out, T val) { | |
using uint_t = typename std::make_unsigned<T>::type; | |
uint_t valu; | |
std::memcpy(&valu, &val, sizeof(T)); | |
EndianBaseImpl::Write(std::forward<Dst>(out), EndianHandler{}, valu); | |
} | |
}; | |
} // namespace detail | |
template <typename Src> | |
FORCE_INLINE auto Read1(Src&& in) -> size_t { | |
return detail::EndianBaseImpl::template Read<uint8_t>(std::forward<Src>(in), detail::EndianIdentity{}); | |
} | |
template <typename Dst> | |
FORCE_INLINE void Write1(Dst&& out, size_t const val) { | |
detail::EndianBaseImpl::Write(std::forward<Dst>(out), detail::EndianIdentity{}, uint8_t(val)); | |
} | |
#ifdef ENDIANIO_LITTLE_ENDIAN | |
using BigEndian = detail::EndianBase<detail::EndianReverse>; | |
using LittleEndian = detail::EndianBase<detail::EndianIdentity>; | |
#elif defined(ENDIANIO_BIG_ENDIAN) | |
using BigEndian = detail::EndianBase<detail::EndianIdentity>; | |
using LittleEndian = detail::EndianBase<detail::EndianReverse>; | |
#endif | |
#endif | |
#include <vector> | |
#include <deque> | |
#include <list> | |
#include <string> | |
#include <sstream> | |
#include <fstream> | |
//NOLINTNEXTLINE(google-build-using-namespace,google-global-names-in-headers) | |
using namespace std; | |
namespace DoBigEndian { | |
using uint_t = uint32_t; | |
using Endian = BigEndian; | |
auto testR1(const uint8_t*& cc) { | |
return Endian::Read<uint_t>(cc); | |
} | |
auto testR1(vector<uint8_t>::const_iterator& cc) { | |
return Endian::Read<uint_t>(cc); | |
} | |
auto testR1(deque<uint8_t>::const_iterator& cc) { | |
return Endian::Read<uint_t>(cc); | |
} | |
auto testR1(list<uint8_t>::const_iterator& cc) { | |
return Endian::Read<uint_t>(cc); | |
} | |
auto testR1(string::const_iterator& cc) { | |
return Endian::Read<uint_t>(cc); | |
} | |
ATTR_PURE auto testR2(const uint8_t* cc) { | |
return Endian::Read<uint_t>(cc); | |
} | |
ATTR_PURE auto testR2(vector<uint8_t>::const_iterator cc) { | |
return Endian::Read<uint_t>(cc); | |
} | |
ATTR_PURE auto testR2(deque<uint8_t>::const_iterator cc) { | |
return Endian::Read<uint_t>(cc); | |
} | |
ATTR_PURE auto testR2(list<uint8_t>::const_iterator cc) { | |
return Endian::Read<uint_t>(cc); | |
} | |
ATTR_PURE auto testR2(string::const_iterator cc) { | |
return Endian::Read<uint_t>(cc); | |
} | |
auto testR3(std::reverse_iterator<const uint8_t*>& cc) { | |
return Endian::Read<uint_t>(cc); | |
} | |
auto testR3(vector<uint8_t>::const_reverse_iterator& cc) { | |
return Endian::Read<uint_t>(cc); | |
} | |
auto testR3(deque<uint8_t>::const_reverse_iterator& cc) { | |
return Endian::Read<uint_t>(cc); | |
} | |
auto testR3(list<uint8_t>::const_reverse_iterator& cc) { | |
return Endian::Read<uint_t>(cc); | |
} | |
auto testR3(string::const_reverse_iterator& cc) { | |
return Endian::Read<uint_t>(cc); | |
} | |
auto testR4(ifstream& cc) { | |
return Endian::Read<uint_t>(cc); | |
} | |
auto testR4(istringstream& cc) { | |
return Endian::Read<uint_t>(cc); | |
} | |
auto testR4(filebuf& cc) { | |
return Endian::Read<uint_t>(cc); | |
} | |
auto testR4(stringbuf& cc) { | |
return Endian::Read<uint_t>(cc); | |
} | |
auto testW1(uint8_t*& cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW1(vector<uint8_t>::iterator& cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW1(deque<uint8_t>::iterator& cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW1(list<uint8_t>::iterator& cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW1(string::iterator& cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW2(uint8_t* cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW2(vector<uint8_t>::iterator cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW2(deque<uint8_t>::iterator cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW2(list<uint8_t>::iterator cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW2(string::iterator cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW3(std::reverse_iterator<uint8_t*>& cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW3(vector<uint8_t>::reverse_iterator& cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW3(deque<uint8_t>::reverse_iterator& cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW3(list<uint8_t>::reverse_iterator& cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW3(string::reverse_iterator& cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW4(vector<uint8_t>& cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW4(deque<uint8_t>& cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW4(list<uint8_t>& cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW4(string& cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW4(ofstream& cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW4(ostringstream& cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW4(filebuf& cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW4(stringbuf& cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW5(vector<uint8_t>& cc, uint_t vv) { | |
auto it = back_inserter(cc); | |
Endian::Write(it, vv); | |
} | |
auto testW5(deque<uint8_t>& cc, uint_t vv) { | |
auto it = back_inserter(cc); | |
Endian::Write(it, vv); | |
} | |
auto testW5(list<uint8_t>& cc, uint_t vv) { | |
auto it = back_inserter(cc); | |
Endian::Write(it, vv); | |
} | |
auto testW5(string& cc, uint_t vv) { | |
auto it = back_inserter(cc); | |
Endian::Write(it, vv); | |
} | |
} // namespace DoBigEndian | |
namespace DoLittleEndian { | |
using uint_t = uint32_t; | |
using Endian = LittleEndian; | |
auto testR1(const uint8_t*& cc) { | |
return Endian::Read<uint_t>(cc); | |
} | |
auto testR1(vector<uint8_t>::const_iterator& cc) { | |
return Endian::Read<uint_t>(cc); | |
} | |
auto testR1(deque<uint8_t>::const_iterator& cc) { | |
return Endian::Read<uint_t>(cc); | |
} | |
auto testR1(list<uint8_t>::const_iterator& cc) { | |
return Endian::Read<uint_t>(cc); | |
} | |
auto testR1(string::const_iterator& cc) { | |
return Endian::Read<uint_t>(cc); | |
} | |
ATTR_PURE auto testR2(const uint8_t* cc) { | |
return Endian::Read<uint_t>(cc); | |
} | |
ATTR_PURE auto testR2(vector<uint8_t>::const_iterator cc) { | |
return Endian::Read<uint_t>(cc); | |
} | |
ATTR_PURE auto testR2(deque<uint8_t>::const_iterator cc) { | |
return Endian::Read<uint_t>(cc); | |
} | |
ATTR_PURE auto testR2(list<uint8_t>::const_iterator cc) { | |
return Endian::Read<uint_t>(cc); | |
} | |
ATTR_PURE auto testR2(string::const_iterator cc) { | |
return Endian::Read<uint_t>(cc); | |
} | |
auto testR3(std::reverse_iterator<const uint8_t*>& cc) { | |
return Endian::Read<uint_t>(cc); | |
} | |
auto testR3(vector<uint8_t>::const_reverse_iterator& cc) { | |
return Endian::Read<uint_t>(cc); | |
} | |
auto testR3(deque<uint8_t>::const_reverse_iterator& cc) { | |
return Endian::Read<uint_t>(cc); | |
} | |
auto testR3(list<uint8_t>::const_reverse_iterator& cc) { | |
return Endian::Read<uint_t>(cc); | |
} | |
auto testR3(string::const_reverse_iterator& cc) { | |
return Endian::Read<uint_t>(cc); | |
} | |
auto testR4(ifstream& cc) { | |
return Endian::Read<uint_t>(cc); | |
} | |
auto testR4(istringstream& cc) { | |
return Endian::Read<uint_t>(cc); | |
} | |
auto testR4(filebuf& cc) { | |
return Endian::Read<uint_t>(cc); | |
} | |
auto testR4(stringbuf& cc) { | |
return Endian::Read<uint_t>(cc); | |
} | |
auto testW1(uint8_t*& cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW1(vector<uint8_t>::iterator& cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW1(deque<uint8_t>::iterator& cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW1(list<uint8_t>::iterator& cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW1(string::iterator& cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW2(uint8_t* cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW2(vector<uint8_t>::iterator cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW2(deque<uint8_t>::iterator cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW2(list<uint8_t>::iterator cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW2(string::iterator cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW3(std::reverse_iterator<uint8_t*>& cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW3(vector<uint8_t>::reverse_iterator& cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW3(deque<uint8_t>::reverse_iterator& cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW3(list<uint8_t>::reverse_iterator& cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW3(string::reverse_iterator& cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW4(vector<uint8_t>& cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW4(deque<uint8_t>& cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW4(list<uint8_t>& cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW4(string& cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW4(ofstream& cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW4(ostringstream& cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW4(filebuf& cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW4(stringbuf& cc, uint_t vv) { | |
Endian::Write(cc, vv); | |
} | |
auto testW5(vector<uint8_t>& cc, uint_t vv) { | |
auto it = back_inserter(cc); | |
Endian::Write(it, vv); | |
} | |
auto testW5(deque<uint8_t>& cc, uint_t vv) { | |
auto it = back_inserter(cc); | |
Endian::Write(it, vv); | |
} | |
auto testW5(list<uint8_t>& cc, uint_t vv) { | |
auto it = back_inserter(cc); | |
Endian::Write(it, vv); | |
} | |
auto testW5(string& cc, uint_t vv) { | |
auto it = back_inserter(cc); | |
Endian::Write(it, vv); | |
} | |
} // namespace DoLittleEndian |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment