From 2a5a29699273ac2e446cd433683d11579b1ee17d Mon Sep 17 00:00:00 2001 From: tpoisonooo Date: Mon, 13 Jun 2022 17:14:01 +0800 Subject: [PATCH 01/15] feat(tools/quantize): support toml --- tools/quantize/CMakeLists.txt | 1 + tools/quantize/helper/cmdline.h | 827 ++++ tools/quantize/helper/toml++/impl/array.h | 1716 ++++++++ tools/quantize/helper/toml++/impl/array.inl | 378 ++ tools/quantize/helper/toml++/impl/at_path.h | 82 + tools/quantize/helper/toml++/impl/at_path.inl | 227 + tools/quantize/helper/toml++/impl/date_time.h | 462 ++ tools/quantize/helper/toml++/impl/formatter.h | 185 + .../quantize/helper/toml++/impl/formatter.inl | 513 +++ .../helper/toml++/impl/forward_declarations.h | 1072 +++++ .../quantize/helper/toml++/impl/header_end.h | 10 + .../helper/toml++/impl/header_start.h | 12 + tools/quantize/helper/toml++/impl/key.h | 335 ++ tools/quantize/helper/toml++/impl/make_node.h | 159 + tools/quantize/helper/toml++/impl/node.h | 1045 +++++ tools/quantize/helper/toml++/impl/node.inl | 116 + tools/quantize/helper/toml++/impl/node_view.h | 818 ++++ .../quantize/helper/toml++/impl/parse_error.h | 139 + .../helper/toml++/impl/parse_result.h | 455 ++ tools/quantize/helper/toml++/impl/parser.h | 388 ++ tools/quantize/helper/toml++/impl/parser.inl | 3887 +++++++++++++++++ .../helper/toml++/impl/preprocessor.h | 1139 +++++ .../helper/toml++/impl/print_to_stream.h | 124 + .../helper/toml++/impl/print_to_stream.inl | 472 ++ tools/quantize/helper/toml++/impl/simd.h | 35 + .../helper/toml++/impl/source_region.h | 195 + .../quantize/helper/toml++/impl/std_except.h | 12 + .../helper/toml++/impl/std_initializer_list.h | 10 + tools/quantize/helper/toml++/impl/std_map.h | 11 + tools/quantize/helper/toml++/impl/std_new.h | 18 + .../helper/toml++/impl/std_optional.h | 32 + .../quantize/helper/toml++/impl/std_string.h | 53 + .../helper/toml++/impl/std_string.inl | 99 + .../quantize/helper/toml++/impl/std_utility.h | 10 + .../quantize/helper/toml++/impl/std_vector.h | 11 + tools/quantize/helper/toml++/impl/table.h | 1954 +++++++++ tools/quantize/helper/toml++/impl/table.inl | 310 ++ .../helper/toml++/impl/toml_formatter.h | 153 + .../helper/toml++/impl/toml_formatter.inl | 396 ++ tools/quantize/helper/toml++/impl/unicode.h | 197 + tools/quantize/helper/toml++/impl/unicode.inl | 59 + .../toml++/impl/unicode_autogenerated.h | 182 + tools/quantize/helper/toml++/impl/value.h | 1259 ++++++ tools/quantize/helper/toml++/impl/version.h | 13 + tools/quantize/helper/toml++/toml.h | 186 + tools/quantize/ncnn2int8_toml.cpp | 87 + tools/quantize/ncnn2table.cpp | 93 +- tools/quantize/net_quantize.cpp | 438 ++ tools/quantize/net_quantize.h | 22 + 49 files changed, 20389 insertions(+), 8 deletions(-) create mode 100644 tools/quantize/helper/cmdline.h create mode 100644 tools/quantize/helper/toml++/impl/array.h create mode 100644 tools/quantize/helper/toml++/impl/array.inl create mode 100644 tools/quantize/helper/toml++/impl/at_path.h create mode 100644 tools/quantize/helper/toml++/impl/at_path.inl create mode 100644 tools/quantize/helper/toml++/impl/date_time.h create mode 100644 tools/quantize/helper/toml++/impl/formatter.h create mode 100644 tools/quantize/helper/toml++/impl/formatter.inl create mode 100644 tools/quantize/helper/toml++/impl/forward_declarations.h create mode 100644 tools/quantize/helper/toml++/impl/header_end.h create mode 100644 tools/quantize/helper/toml++/impl/header_start.h create mode 100644 tools/quantize/helper/toml++/impl/key.h create mode 100644 tools/quantize/helper/toml++/impl/make_node.h create mode 100644 tools/quantize/helper/toml++/impl/node.h create mode 100644 tools/quantize/helper/toml++/impl/node.inl create mode 100644 tools/quantize/helper/toml++/impl/node_view.h create mode 100644 tools/quantize/helper/toml++/impl/parse_error.h create mode 100644 tools/quantize/helper/toml++/impl/parse_result.h create mode 100644 tools/quantize/helper/toml++/impl/parser.h create mode 100644 tools/quantize/helper/toml++/impl/parser.inl create mode 100644 tools/quantize/helper/toml++/impl/preprocessor.h create mode 100644 tools/quantize/helper/toml++/impl/print_to_stream.h create mode 100644 tools/quantize/helper/toml++/impl/print_to_stream.inl create mode 100644 tools/quantize/helper/toml++/impl/simd.h create mode 100644 tools/quantize/helper/toml++/impl/source_region.h create mode 100644 tools/quantize/helper/toml++/impl/std_except.h create mode 100644 tools/quantize/helper/toml++/impl/std_initializer_list.h create mode 100644 tools/quantize/helper/toml++/impl/std_map.h create mode 100644 tools/quantize/helper/toml++/impl/std_new.h create mode 100644 tools/quantize/helper/toml++/impl/std_optional.h create mode 100644 tools/quantize/helper/toml++/impl/std_string.h create mode 100644 tools/quantize/helper/toml++/impl/std_string.inl create mode 100644 tools/quantize/helper/toml++/impl/std_utility.h create mode 100644 tools/quantize/helper/toml++/impl/std_vector.h create mode 100644 tools/quantize/helper/toml++/impl/table.h create mode 100644 tools/quantize/helper/toml++/impl/table.inl create mode 100644 tools/quantize/helper/toml++/impl/toml_formatter.h create mode 100644 tools/quantize/helper/toml++/impl/toml_formatter.inl create mode 100644 tools/quantize/helper/toml++/impl/unicode.h create mode 100644 tools/quantize/helper/toml++/impl/unicode.inl create mode 100644 tools/quantize/helper/toml++/impl/unicode_autogenerated.h create mode 100644 tools/quantize/helper/toml++/impl/value.h create mode 100644 tools/quantize/helper/toml++/impl/version.h create mode 100644 tools/quantize/helper/toml++/toml.h create mode 100644 tools/quantize/ncnn2int8_toml.cpp create mode 100644 tools/quantize/net_quantize.cpp create mode 100644 tools/quantize/net_quantize.h diff --git a/tools/quantize/CMakeLists.txt b/tools/quantize/CMakeLists.txt index 72c76d135015..6fb61e00df94 100644 --- a/tools/quantize/CMakeLists.txt +++ b/tools/quantize/CMakeLists.txt @@ -1,3 +1,4 @@ +set(CMAKE_CXX_STANDARD 17) if(NCNN_PIXEL) if(NOT NCNN_SIMPLEOCV) diff --git a/tools/quantize/helper/cmdline.h b/tools/quantize/helper/cmdline.h new file mode 100644 index 000000000000..8f9f6383a86f --- /dev/null +++ b/tools/quantize/helper/cmdline.h @@ -0,0 +1,827 @@ +/* + Copyright (c) 2009, Hideyuki Tanaka + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace cmdline{ + +namespace detail{ + +template +class lexical_cast_t{ +public: + static Target cast(const Source &arg){ + Target ret; + std::stringstream ss; + if (!(ss<>ret && ss.eof())) + throw std::bad_cast(); + + return ret; + } +}; + +template +class lexical_cast_t{ +public: + static Target cast(const Source &arg){ + return arg; + } +}; + +template +class lexical_cast_t{ +public: + static std::string cast(const Source &arg){ + std::ostringstream ss; + ss< +class lexical_cast_t{ +public: + static Target cast(const std::string &arg){ + Target ret; + std::istringstream ss(arg); + if (!(ss>>ret && ss.eof())) + throw std::bad_cast(); + return ret; + } +}; + +template +struct is_same { + static const bool value = false; +}; + +template +struct is_same{ + static const bool value = true; +}; + +template +Target lexical_cast(const Source &arg) +{ + return lexical_cast_t::value>::cast(arg); +} + + +#ifndef WIN32 +#include + +// https://github.com/tanakh/cmdline/issues/6 +static inline std::string demangle(const std::string &name) +{ + int status=0; + char *p=abi::__cxa_demangle(name.c_str(), 0, 0, &status); + std::string ret(p); + free(p); + return ret; +} +#else + +#include +#include +#pragma comment(lib,"dbghelp.lib") + +static inline std::string demangle(const std::string &name) +{ + TCHAR szUndecorateName[256]; + memset(szUndecorateName, 0, 256); + UnDecorateSymbolName(name.c_str(), szUndecorateName, 256, 0); + return szUndecorateName; +} +#endif + +template +std::string readable_typename() +{ + return demangle(typeid(T).name()); +} + +template +std::string default_value(T def) +{ + return detail::lexical_cast(def); +} + +template <> +inline std::string readable_typename() +{ + return "string"; +} + +} // detail + +//----- + +class cmdline_error : public std::exception { +public: + cmdline_error(const std::string &msg): msg(msg){} + ~cmdline_error() throw() {} + const char *what() const throw() { return msg.c_str(); } +private: + std::string msg; +}; + +template +struct default_reader{ + T operator()(const std::string &str){ + return detail::lexical_cast(str); + } +}; + +template +struct range_reader{ + range_reader(const T &low, const T &high): low(low), high(high) {} + T operator()(const std::string &s) const { + T ret=default_reader()(s); + if (!(ret>=low && ret<=high)) throw cmdline::cmdline_error("range_error"); + return ret; + } +private: + T low, high; +}; + +template +range_reader range(const T &low, const T &high) +{ + return range_reader(low, high); +} + +template +struct oneof_reader{ + T operator()(const std::string &s){ + T ret=default_reader()(s); + if (std::find(alt.begin(), alt.end(), ret)==alt.end()) + throw cmdline_error(""); + return ret; + } + void add(const T &v){ alt.push_back(v); } +private: + std::vector alt; +}; + +template +oneof_reader oneof(T a1) +{ + oneof_reader ret; + ret.add(a1); + return ret; +} + +template +oneof_reader oneof(T a1, T a2) +{ + oneof_reader ret; + ret.add(a1); + ret.add(a2); + return ret; +} + +template +oneof_reader oneof(T a1, T a2, T a3) +{ + oneof_reader ret; + ret.add(a1); + ret.add(a2); + ret.add(a3); + return ret; +} + +template +oneof_reader oneof(T a1, T a2, T a3, T a4) +{ + oneof_reader ret; + ret.add(a1); + ret.add(a2); + ret.add(a3); + ret.add(a4); + return ret; +} + +template +oneof_reader oneof(T a1, T a2, T a3, T a4, T a5) +{ + oneof_reader ret; + ret.add(a1); + ret.add(a2); + ret.add(a3); + ret.add(a4); + ret.add(a5); + return ret; +} + +template +oneof_reader oneof(T a1, T a2, T a3, T a4, T a5, T a6) +{ + oneof_reader ret; + ret.add(a1); + ret.add(a2); + ret.add(a3); + ret.add(a4); + ret.add(a5); + ret.add(a6); + return ret; +} + +template +oneof_reader oneof(T a1, T a2, T a3, T a4, T a5, T a6, T a7) +{ + oneof_reader ret; + ret.add(a1); + ret.add(a2); + ret.add(a3); + ret.add(a4); + ret.add(a5); + ret.add(a6); + ret.add(a7); + return ret; +} + +template +oneof_reader oneof(T a1, T a2, T a3, T a4, T a5, T a6, T a7, T a8) +{ + oneof_reader ret; + ret.add(a1); + ret.add(a2); + ret.add(a3); + ret.add(a4); + ret.add(a5); + ret.add(a6); + ret.add(a7); + ret.add(a8); + return ret; +} + +template +oneof_reader oneof(T a1, T a2, T a3, T a4, T a5, T a6, T a7, T a8, T a9) +{ + oneof_reader ret; + ret.add(a1); + ret.add(a2); + ret.add(a3); + ret.add(a4); + ret.add(a5); + ret.add(a6); + ret.add(a7); + ret.add(a8); + ret.add(a9); + return ret; +} + +template +oneof_reader oneof(T a1, T a2, T a3, T a4, T a5, T a6, T a7, T a8, T a9, T a10) +{ + oneof_reader ret; + ret.add(a1); + ret.add(a2); + ret.add(a3); + ret.add(a4); + ret.add(a5); + ret.add(a6); + ret.add(a7); + ret.add(a8); + ret.add(a9); + ret.add(a10); + return ret; +} + +//----- + +class parser{ +public: + parser(){ + } + ~parser(){ + for (std::map::iterator p=options.begin(); + p!=options.end(); p++) + delete p->second; + } + + void add(const std::string &name, + char short_name=0, + const std::string &desc=""){ + if (options.count(name)) throw cmdline_error("multiple definition: "+name); + options[name]=new option_without_value(name, short_name, desc); + ordered.push_back(options[name]); + } + + template + void add(const std::string &name, + char short_name=0, + const std::string &desc="", + bool need=true, + const T def=T()){ + add(name, short_name, desc, need, def, default_reader()); + } + + template + void add(const std::string &name, + char short_name=0, + const std::string &desc="", + bool need=true, + const T def=T(), + F reader=F()){ + if (options.count(name)) throw cmdline_error("multiple definition: "+name); + options[name]=new option_with_value_with_reader(name, short_name, need, def, desc, reader); + ordered.push_back(options[name]); + } + + void footer(const std::string &f){ + ftr=f; + } + + void set_program_name(const std::string &name){ + prog_name=name; + } + + bool exist(const std::string &name) const { + if (options.count(name)==0) throw cmdline_error("there is no flag: --"+name); + return options.find(name)->second->has_set(); + } + + template + const T &get(const std::string &name) const { + if (options.count(name)==0) throw cmdline_error("there is no flag: --"+name); + const option_with_value *p=dynamic_cast*>(options.find(name)->second); + if (p==NULL) throw cmdline_error("type mismatch flag '"+name+"'"); + return p->get(); + } + + const std::vector &rest() const { + return others; + } + + bool parse(const std::string &arg){ + std::vector args; + + std::string buf; + bool in_quote=false; + for (std::string::size_type i=0; i=arg.length()){ + errors.push_back("unexpected occurrence of '\\' at end of string"); + return false; + } + } + + buf+=arg[i]; + } + + if (in_quote){ + errors.push_back("quote is not closed"); + return false; + } + + if (buf.length()>0) + args.push_back(buf); + + for (size_t i=0; i &args){ + int argc=static_cast(args.size()); + std::vector argv(argc); + + for (int i=0; i lookup; + for (std::map::iterator p=options.begin(); + p!=options.end(); p++){ + if (p->first.length()==0) continue; + char initial=p->second->short_name(); + if (initial){ + if (lookup.count(initial)>0){ + lookup[initial]=""; + errors.push_back(std::string("short option '")+initial+"' is ambiguous"); + return false; + } + else lookup[initial]=p->first; + } + } + + for (int i=1; i &args){ + if (!options.count("help")) + add("help", '?', "print this message"); + check(args.size(), parse(args)); + } + + void parse_check(int argc, char *argv[]){ + if (!options.count("help")) + add("help", '?', "print this message"); + check(argc, parse(argc, argv)); + } + + std::string error() const{ + return errors.size()>0?errors[0]:""; + } + + std::string error_full() const{ + std::ostringstream oss; + for (size_t i=0; imust()) + oss<short_description()<<" "; + } + + oss<<"[options] ... "<name().length()); + } + for (size_t i=0; ishort_name()){ + oss<<" -"<short_name()<<", "; + } + else{ + oss<<" "; + } + + oss<<"--"<name(); + for (size_t j=ordered[i]->name().length(); jdescription()<set()){ + errors.push_back("option needs value: --"+name); + return; + } + } + + void set_option(const std::string &name, const std::string &value){ + if (options.count(name)==0){ + errors.push_back("undefined option: --"+name); + return; + } + if (!options[name]->set(value)){ + errors.push_back("option value is invalid: --"+name+"="+value); + return; + } + } + + class option_base{ + public: + virtual ~option_base(){} + + virtual bool has_value() const=0; + virtual bool set()=0; + virtual bool set(const std::string &value)=0; + virtual bool has_set() const=0; + virtual bool valid() const=0; + virtual bool must() const=0; + + virtual const std::string &name() const=0; + virtual char short_name() const=0; + virtual const std::string &description() const=0; + virtual std::string short_description() const=0; + }; + + class option_without_value : public option_base { + public: + option_without_value(const std::string &name, + char short_name, + const std::string &desc) + :nam(name), snam(short_name), desc(desc), has(false){ + } + ~option_without_value(){} + + bool has_value() const { return false; } + + bool set(){ + has=true; + return true; + } + + bool set(const std::string &){ + return false; + } + + bool has_set() const { + return has; + } + + bool valid() const{ + return true; + } + + bool must() const{ + return false; + } + + const std::string &name() const{ + return nam; + } + + char short_name() const{ + return snam; + } + + const std::string &description() const { + return desc; + } + + std::string short_description() const{ + return "--"+nam; + } + + private: + std::string nam; + char snam; + std::string desc; + bool has; + }; + + template + class option_with_value : public option_base { + public: + option_with_value(const std::string &name, + char short_name, + bool need, + const T &def, + const std::string &desc) + : nam(name), snam(short_name), need(need), has(false) + , def(def), actual(def) { + this->desc=full_description(desc); + } + ~option_with_value(){} + + const T &get() const { + return actual; + } + + bool has_value() const { return true; } + + bool set(){ + return false; + } + + bool set(const std::string &value){ + try{ + actual=read(value); + has=true; + } + catch(const std::exception &e){ + return false; + } + return true; + } + + bool has_set() const{ + return has; + } + + bool valid() const{ + if (need && !has) return false; + return true; + } + + bool must() const{ + return need; + } + + const std::string &name() const{ + return nam; + } + + char short_name() const{ + return snam; + } + + const std::string &description() const { + return desc; + } + + std::string short_description() const{ + return "--"+nam+"="+detail::readable_typename(); + } + + protected: + std::string full_description(const std::string &desc){ + return + desc+" ("+detail::readable_typename()+ + (need?"":" [="+detail::default_value(def)+"]") + +")"; + } + + virtual T read(const std::string &s)=0; + + std::string nam; + char snam; + bool need; + std::string desc; + + bool has; + T def; + T actual; + }; + + template + class option_with_value_with_reader : public option_with_value { + public: + option_with_value_with_reader(const std::string &name, + char short_name, + bool need, + const T def, + const std::string &desc, + F reader) + : option_with_value(name, short_name, need, def, desc), reader(reader){ + } + + private: + T read(const std::string &s){ + return reader(s); + } + + F reader; + }; + + std::map options; + std::vector ordered; + std::string ftr; + + std::string prog_name; + std::vector others; + + std::vector errors; +}; + +} // cmdline \ No newline at end of file diff --git a/tools/quantize/helper/toml++/impl/array.h b/tools/quantize/helper/toml++/impl/array.h new file mode 100644 index 000000000000..583ae0d211e5 --- /dev/null +++ b/tools/quantize/helper/toml++/impl/array.h @@ -0,0 +1,1716 @@ +//# This file is a part of toml++ and is subject to the the terms of the MIT license. +//# Copyright (c) Mark Gillard +//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. +// SPDX-License-Identifier: MIT +#pragma once + +#include "std_utility.h" +#include "std_vector.h" +#include "std_initializer_list.h" +#include "value.h" +#include "make_node.h" +#include "header_start.h" + +/// \cond +TOML_IMPL_NAMESPACE_START +{ + template + class TOML_TRIVIAL_ABI array_iterator + { + private: + template + friend class array_iterator; + + using mutable_vector_iterator = std::vector::iterator; + using const_vector_iterator = std::vector::const_iterator; + using vector_iterator = std::conditional_t; + + mutable vector_iterator iter_; + + public: + using value_type = std::conditional_t; + using reference = value_type&; + using pointer = value_type*; + using difference_type = ptrdiff_t; + using iterator_category = typename std::iterator_traits::iterator_category; + + TOML_NODISCARD_CTOR + array_iterator() noexcept = default; + + TOML_NODISCARD_CTOR + explicit array_iterator(mutable_vector_iterator iter) noexcept // + : iter_{ iter } + {} + + TOML_CONSTRAINED_TEMPLATE(C, bool C = IsConst) + TOML_NODISCARD_CTOR + explicit array_iterator(const_vector_iterator iter) noexcept // + : iter_{ iter } + {} + + TOML_CONSTRAINED_TEMPLATE(C, bool C = IsConst) + TOML_NODISCARD_CTOR + array_iterator(const array_iterator& other) noexcept // + : iter_{ other.iter_ } + {} + + TOML_NODISCARD_CTOR + array_iterator(const array_iterator&) noexcept = default; + + array_iterator& operator=(const array_iterator&) noexcept = default; + + array_iterator& operator++() noexcept // ++pre + { + ++iter_; + return *this; + } + + array_iterator operator++(int) noexcept // post++ + { + array_iterator out{ iter_ }; + ++iter_; + return out; + } + + array_iterator& operator--() noexcept // --pre + { + --iter_; + return *this; + } + + array_iterator operator--(int) noexcept // post-- + { + array_iterator out{ iter_ }; + --iter_; + return out; + } + + TOML_PURE_INLINE_GETTER + reference operator*() const noexcept + { + return *iter_->get(); + } + + TOML_PURE_INLINE_GETTER + pointer operator->() const noexcept + { + return iter_->get(); + } + + TOML_PURE_INLINE_GETTER + explicit operator const vector_iterator&() const noexcept + { + return iter_; + } + + TOML_CONSTRAINED_TEMPLATE(!C, bool C = IsConst) + TOML_PURE_INLINE_GETTER + explicit operator const const_vector_iterator() const noexcept + { + return iter_; + } + + array_iterator& operator+=(ptrdiff_t rhs) noexcept + { + iter_ += rhs; + return *this; + } + + array_iterator& operator-=(ptrdiff_t rhs) noexcept + { + iter_ -= rhs; + return *this; + } + + TOML_NODISCARD + friend array_iterator operator+(const array_iterator& lhs, ptrdiff_t rhs) noexcept + { + return array_iterator{ lhs.iter_ + rhs }; + } + + TOML_NODISCARD + friend array_iterator operator+(ptrdiff_t lhs, const array_iterator& rhs) noexcept + { + return array_iterator{ rhs.iter_ + lhs }; + } + + TOML_NODISCARD + friend array_iterator operator-(const array_iterator& lhs, ptrdiff_t rhs) noexcept + { + return array_iterator{ lhs.iter_ - rhs }; + } + + TOML_PURE_INLINE_GETTER + friend ptrdiff_t operator-(const array_iterator& lhs, const array_iterator& rhs) noexcept + { + return lhs.iter_ - rhs.iter_; + } + + TOML_PURE_INLINE_GETTER + friend bool operator==(const array_iterator& lhs, const array_iterator& rhs) noexcept + { + return lhs.iter_ == rhs.iter_; + } + + TOML_PURE_INLINE_GETTER + friend bool operator!=(const array_iterator& lhs, const array_iterator& rhs) noexcept + { + return lhs.iter_ != rhs.iter_; + } + + TOML_PURE_INLINE_GETTER + friend bool operator<(const array_iterator& lhs, const array_iterator& rhs) noexcept + { + return lhs.iter_ < rhs.iter_; + } + + TOML_PURE_INLINE_GETTER + friend bool operator<=(const array_iterator& lhs, const array_iterator& rhs) noexcept + { + return lhs.iter_ <= rhs.iter_; + } + + TOML_PURE_INLINE_GETTER + friend bool operator>(const array_iterator& lhs, const array_iterator& rhs) noexcept + { + return lhs.iter_ > rhs.iter_; + } + + TOML_PURE_INLINE_GETTER + friend bool operator>=(const array_iterator& lhs, const array_iterator& rhs) noexcept + { + return lhs.iter_ >= rhs.iter_; + } + + TOML_PURE_INLINE_GETTER + reference operator[](ptrdiff_t idx) const noexcept + { + return *(iter_ + idx)->get(); + } + }; + + struct array_init_elem + { + mutable node_ptr value; + + template + TOML_NODISCARD_CTOR + array_init_elem(T&& val, value_flags flags = preserve_source_value_flags) // + : value{ make_node(static_cast(val), flags) } + {} + }; +} +TOML_IMPL_NAMESPACE_END; +/// \endcond + +TOML_NAMESPACE_START +{ + /// \brief A RandomAccessIterator for iterating over elements in a toml::array. + using array_iterator = POXY_IMPLEMENTATION_DETAIL(impl::array_iterator); + + /// \brief A RandomAccessIterator for iterating over const elements in a toml::array. + using const_array_iterator = POXY_IMPLEMENTATION_DETAIL(impl::array_iterator); + + /// \brief A TOML array. + /// + /// \detail The interface of this type is modeled after std::vector, with some + /// additional considerations made for the heterogeneous nature of a + /// TOML array. + /// + /// \godbolt{sjK4da} + /// + /// \cpp + /// + /// toml::table tbl = toml::parse(R"( + /// arr = [1, 2, 3, 4, 'five'] + /// )"sv); + /// + /// // get the element as an array + /// toml::array& arr = *tbl.get_as("arr"); + /// std::cout << arr << "\n"; + /// + /// // increment each element with visit() + /// for (auto&& elem : arr) + /// { + /// elem.visit([](auto&& el) noexcept + /// { + /// if constexpr (toml::is_number) + /// (*el)++; + /// else if constexpr (toml::is_string) + /// el = "six"sv; + /// }); + /// } + /// std::cout << arr << "\n"; + /// + /// // add and remove elements + /// arr.push_back(7); + /// arr.push_back(8.0f); + /// arr.push_back("nine"sv); + /// arr.erase(arr.cbegin()); + /// std::cout << arr << "\n"; + /// + /// // emplace elements + /// arr.emplace_back("ten"); + /// arr.emplace_back(11, 12.0); + /// std::cout << arr << "\n"; + /// \ecpp + /// + /// \out + /// [ 1, 2, 3, 4, 'five' ] + /// [ 2, 3, 4, 5, 'six' ] + /// [ 3, 4, 5, 'six', 7, 8.0, 'nine' ] + /// [ 3, 4, 5, 'six', 7, 8.0, 'nine', 'ten', [ 11, 12.0 ] ] + /// \eout + class TOML_EXPORTED_CLASS array : public node + { + private: + /// \cond + + using vector_type = std::vector; + using vector_iterator = typename vector_type::iterator; + using const_vector_iterator = typename vector_type::const_iterator; + vector_type elems_; + + TOML_NODISCARD_CTOR + TOML_EXPORTED_MEMBER_FUNCTION + array(const impl::array_init_elem*, const impl::array_init_elem*); + + TOML_NODISCARD_CTOR + array(std::false_type, std::initializer_list elems) // + : array{ elems.begin(), elems.end() } + {} + + TOML_EXPORTED_MEMBER_FUNCTION + void preinsertion_resize(size_t idx, size_t count); + + TOML_EXPORTED_MEMBER_FUNCTION + void insert_at_back(impl::node_ptr&&); + + TOML_EXPORTED_MEMBER_FUNCTION + vector_iterator insert_at(const_vector_iterator, impl::node_ptr&&); + + template + void emplace_back_if_not_empty_view(T&& val, value_flags flags) + { + if constexpr (is_node_view) + { + if (!val) + return; + } + insert_at_back(impl::make_node(static_cast(val), flags)); + } + + TOML_NODISCARD + TOML_EXPORTED_MEMBER_FUNCTION + size_t total_leaf_count() const noexcept; + + TOML_EXPORTED_MEMBER_FUNCTION + void flatten_child(array&& child, size_t& dest_index) noexcept; + + /// \endcond + + public: + using value_type = node; + using size_type = size_t; + using difference_type = ptrdiff_t; + using reference = node&; + using const_reference = const node&; + + /// \brief Default constructor. + TOML_NODISCARD_CTOR + TOML_EXPORTED_MEMBER_FUNCTION + array() noexcept; + + TOML_EXPORTED_MEMBER_FUNCTION + ~array() noexcept; + + /// \brief Copy constructor. + TOML_NODISCARD_CTOR + TOML_EXPORTED_MEMBER_FUNCTION + array(const array&); + + /// \brief Move constructor. + TOML_NODISCARD_CTOR + TOML_EXPORTED_MEMBER_FUNCTION + array(array&& other) noexcept; + + /// \brief Constructs an array with one or more initial elements. + /// + /// \detail \cpp + /// auto arr = toml::array{ 1, 2.0, "three"sv, toml::array{ 4, 5 } }; + /// std::cout << arr << "\n"; + /// \ecpp + /// + /// \out + /// [ 1, 2.0, 'three', [ 4, 5 ] ] + /// \eout + /// + /// \remark \parblock If you need to construct an array with one child array element, the array's move constructor + /// will take precedence and perform a move-construction instead. You can use toml::inserter to + /// suppress this behaviour: \cpp + /// // desired result: [ [ 42 ] ] + /// auto bad = toml::array{ toml::array{ 42 } } + /// auto good = toml::array{ toml::inserter{ toml::array{ 42 } } } + /// std::cout << "bad: " << bad << "\n"; + /// std::cout << "good:" << good << "\n"; + /// \ecpp + /// + /// \out + /// bad: [ 42 ] + /// good: [ [ 42 ] ] + /// \eout + /// + /// \endparblock + /// + /// \tparam ElemType One of the TOML node or value types (or a type promotable to one). + /// \tparam ElemTypes One of the TOML node or value types (or a type promotable to one). + /// \param val The node or value used to initialize element 0. + /// \param vals The nodes or values used to initialize elements 1...N. + TOML_CONSTRAINED_TEMPLATE((sizeof...(ElemTypes) > 0 || !std::is_same_v, array>), + typename ElemType, + typename... ElemTypes) + TOML_NODISCARD_CTOR + explicit array(ElemType&& val, ElemTypes&&... vals) + : array{ std::false_type{}, + std::initializer_list{ static_cast(val), + static_cast(vals)... } } + {} + + /// \brief Copy-assignment operator. + TOML_EXPORTED_MEMBER_FUNCTION + array& operator=(const array&); + + /// \brief Move-assignment operator. + TOML_EXPORTED_MEMBER_FUNCTION + array& operator=(array&& rhs) noexcept; + + /// \name Type checks + /// @{ + + /// \brief Returns #toml::node_type::array. + TOML_CONST_INLINE_GETTER + node_type type() const noexcept final + { + return node_type::array; + } + + TOML_PURE_GETTER + TOML_EXPORTED_MEMBER_FUNCTION + bool is_homogeneous(node_type ntype) const noexcept final; + + TOML_PURE_GETTER + TOML_EXPORTED_MEMBER_FUNCTION + bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept final; + + TOML_PURE_GETTER + TOML_EXPORTED_MEMBER_FUNCTION + bool is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept final; + + /// \cond + template + TOML_PURE_GETTER + bool is_homogeneous() const noexcept + { + using unwrapped_type = impl::unwrap_node>; + static_assert(std::is_void_v // + || (impl::is_native || impl::is_one_of), + "The template type argument of array::is_homogeneous() must be void or one " + "of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST); + + return is_homogeneous(impl::node_type_of); + } + /// \endcond + + /// \brief Returns `false`. + TOML_CONST_INLINE_GETTER + bool is_table() const noexcept final + { + return false; + } + + /// \brief Returns `true`. + TOML_CONST_INLINE_GETTER + bool is_array() const noexcept final + { + return true; + } + + /// \brief Returns `true` if the array contains only tables. + TOML_PURE_GETTER + bool is_array_of_tables() const noexcept final + { + return is_homogeneous(node_type::table); + } + + /// \brief Returns `false`. + TOML_CONST_INLINE_GETTER + bool is_value() const noexcept final + { + return false; + } + + /// \brief Returns `false`. + TOML_CONST_INLINE_GETTER + bool is_string() const noexcept final + { + return false; + } + + /// \brief Returns `false`. + TOML_CONST_INLINE_GETTER + bool is_integer() const noexcept final + { + return false; + } + + /// \brief Returns `false`. + TOML_CONST_INLINE_GETTER + bool is_floating_point() const noexcept final + { + return false; + } + + /// \brief Returns `false`. + TOML_CONST_INLINE_GETTER + bool is_number() const noexcept final + { + return false; + } + + /// \brief Returns `false`. + TOML_CONST_INLINE_GETTER + bool is_boolean() const noexcept final + { + return false; + } + + /// \brief Returns `false`. + TOML_CONST_INLINE_GETTER + bool is_date() const noexcept final + { + return false; + } + + /// \brief Returns `false`. + TOML_CONST_INLINE_GETTER + bool is_time() const noexcept final + { + return false; + } + + /// \brief Returns `false`. + TOML_CONST_INLINE_GETTER + bool is_date_time() const noexcept final + { + return false; + } + + /// @} + + /// \name Type casts + /// @{ + + /// \brief Returns `nullptr`. + TOML_CONST_INLINE_GETTER + table* as_table() noexcept final + { + return nullptr; + } + + /// \brief Returns a pointer to the array. + TOML_CONST_INLINE_GETTER + array* as_array() noexcept final + { + return this; + } + + /// \brief Returns `nullptr`. + TOML_CONST_INLINE_GETTER + toml::value* as_string() noexcept final + { + return nullptr; + } + + /// \brief Returns `nullptr`. + TOML_CONST_INLINE_GETTER + toml::value* as_integer() noexcept final + { + return nullptr; + } + + /// \brief Returns `nullptr`. + TOML_CONST_INLINE_GETTER + toml::value* as_floating_point() noexcept final + { + return nullptr; + } + + /// \brief Returns `nullptr`. + TOML_CONST_INLINE_GETTER + toml::value* as_boolean() noexcept final + { + return nullptr; + } + + /// \brief Returns `nullptr`. + TOML_CONST_INLINE_GETTER + toml::value* as_date() noexcept final + { + return nullptr; + } + + /// \brief Returns `nullptr`. + TOML_CONST_INLINE_GETTER + toml::value