// A checked, schema-specific FlatBuffers table lesson, NOT a general compiler.
// SPDX-License-Identifier: MIT
#pragma once
#include "flex_wire.hpp"
namespace flexlab::flat {
// table Sample { count:int = 0; name:string; } root_type Sample;
inline Bytes sample(std::int32_t count, std::string_view name) {
 require(name.size()<=UINT32_MAX,"string too long");
 Bytes b;
 store_u(b,12,4);                 // root table at 12
 store_u(b,8,2); store_u(b,12,2); // vtable size, inline object size
 store_u(b,4,2); store_u(b,8,2);  // count and name positions in table
 store_u(b,8,4);                 // table 12 minus displacement 8 -> vtable 4
 store_u(b,std::bit_cast<std::uint32_t>(count),4);
 store_u(b,4,4);                 // name offset at 20 -> length at 24
 store_u(b,name.size(),4);
 b.insert(b.end(),name.begin(),name.end()); b.push_back(0);
 b.resize(align_up(b.size(),4),0); return b;
}
class Sample {
 ByteSpan b_;
 std::size_t table_, vt_;
 std::size_t field(unsigned index, unsigned width) const {
   const auto entry=4+2*index;
   const auto vt_size=load_u(b_,vt_,2);
   if (entry+2>vt_size) return 0;
   const auto off=load_u(b_,vt_+entry,2); if (!off) return 0;
   const auto object_size=load_u(b_,vt_+2,2);
   require(off>=4 && off<=object_size && width<=object_size-off,"field outside inline object");
   const auto p=add(table_,static_cast<std::size_t>(off)); range(b_,p,width); return p;
 }
public:
 explicit Sample(ByteSpan b) : b_(b), table_(0), vt_(0) {
   table_=static_cast<std::size_t>(load_u(b_,0,4)); range(b_,table_,4);
   const auto d=load_i(b_,table_,4);
   if (d>=0) { require(static_cast<std::uint64_t>(d)<=table_,"vtable underflow"); vt_=table_-static_cast<std::size_t>(d); }
   else vt_=add(table_,static_cast<std::size_t>(-d));
   const auto len=load_u(b_,vt_,2);
   require(len>=4 && len%2==0,"bad vtable size"); range(b_,vt_,static_cast<std::size_t>(len));
   const auto object=load_u(b_,vt_+2,2); require(object>=4,"bad inline object size");
   range(b_,table_,static_cast<std::size_t>(object));
 }
 std::int32_t count() const {
   const auto p=field(0,4); return p ? static_cast<std::int32_t>(load_i(b_,p,4)) : 0;
 }
 std::optional<std::string_view> name() const {
   const auto p=field(1,4); if (!p) return std::nullopt;
   const auto q=add(p,static_cast<std::size_t>(load_u(b_,p,4)));
   const auto n=static_cast<std::size_t>(load_u(b_,q,4));
   const auto text=add(q,4); range(b_,text,add(n,1));
   require(b_[text+n]==0,"missing FlatBuffers string terminator");
   return std::string_view(reinterpret_cast<const char*>(b_.data()+text),n);
 }
};
} // namespace flexlab::flat
