binary/OutputArchive.h terse/Archive.h terse/archives/Traits.h terse/types/Anchor.h terse/types/ArchiveOffset.h terse/types/ArchiveSize.h terse/types/Blob.h terse/types/DynArray.h terse/types/Transparent.h terse/utils/ByteSwap.h array cassert cstddef cstdint cstring limits memory string tuple type_traits utility vector BinaryStreamWriterImpl.h terse::ExtendableBinaryOutputArchive terse::BinaryOutputArchive terse //CopyrightEpicGames,Inc.AllRightsReserved. #pragmaonce #include"terse/Archive.h" #include"terse/archives/Traits.h" #include"terse/types/Anchor.h" #include"terse/types/ArchiveOffset.h" #include"terse/types/ArchiveSize.h" #include"terse/types/Blob.h" #include"terse/types/DynArray.h" #include"terse/types/Transparent.h" #include"terse/utils/ByteSwap.h" #ifdef_MSC_VER #pragmawarning(push) #pragmawarning(disable:43654987) #endif #include<array> #include<cassert> #include<cstddef> #include<cstdint> #include<cstring> #include<limits> #include<memory> #include<string> #include<tuple> #include<type_traits> #include<utility> #include<vector> #ifdef_MSC_VER #pragmawarning(pop) #endif namespaceterse{ template<classTExtender,classTStream,typenameTSize,typenameTOffset,EndiannessEByteOrder> classExtendableBinaryOutputArchive:publicArchive<TExtender>{ private: usingBaseArchive=Archive<TExtender>; public: //Giventhepossibilityofboth32and64bitplatforms,useafixedwidthtypeduringserialization usingSizeType=TSize; usingOffsetType=TOffset; staticconstexprEndiannessendianness(){ returnEByteOrder; } public: ExtendableBinaryOutputArchive(TExtender*extender,TStream*stream_):BaseArchive{extender},stream{stream_}{ } boolisOk(){ returntrue; } voidsync(){ } voidlabel(constchar*/*unused*/){ } protected: template<typenameT> voidprocess(Transparent<T>&&source){ process(source.data); } voidprocess(Anchor<OffsetType>&source){ source.value=static_cast<OffsetType>(stream->tell()); } voidprocess(ArchiveOffset<OffsetType>&source){ //Recordthepositionwheretheoffsetisgoingtobewrittensoitcanbeseekedtolaterwhen //itsproxyisfound #if!defined(__clang__)&&defined(__GNUC__) #pragmaGCCdiagnosticpush #pragmaGCCdiagnosticignored"-Wuseless-cast" #endif source.position=static_cast<decltype(source.position)>(stream->tell()); #if!defined(__clang__)&&defined(__GNUC__) #pragmaGCCdiagnosticpop #endif //Sincetheactualoffsetvalueisnotyetknownatthetimewhenitsdeclarationisencountered, //fillitsplacewithzerosasaplaceholder,anditwillbelaterpopulatedwhenitsassociated //proxyisfound process(typenameArchiveOffset<OffsetType>::ValueType{}); } voidprocess(typenameArchiveOffset<OffsetType>::Proxy&source){ //Thecurrentpositionofthestreamneedstobewrittentothepositionwheretheassociated //`ArchiveOffset`isfound. autocurrent=stream->tell(); assert(current<=std::numeric_limits<OffsetType>::max()); source.target->value=static_cast<OffsetType>(current); //Seektotheactualpositionoftheoffsetmarkerandwritethestream'sabovecapturedpositionthere stream->seek(source.target->position); process(static_cast<OffsetType>(current)); //Returntotheearliercapturedstreampositionsoprocessingcansafelyresumefromthere stream->seek(current); } voidprocess(typenameArchiveOffset<OffsetType>::Proxy&&source){ process(source); } voidprocess(ArchiveSize<SizeType, OffsetType>&source){ //Recordthepositionwherethesizeisgoingtobewrittensoitcanbeseekedtolaterwhen //itsproxyisfound #if!defined(__clang__)&&defined(__GNUC__) #pragmaGCCdiagnosticpush #pragmaGCCdiagnosticignored"-Wuseless-cast" #endif source.position=static_cast<decltype(source.position)>(stream->tell()); #if!defined(__clang__)&&defined(__GNUC__) #pragmaGCCdiagnosticpop #endif //Sincetheactualsizevalueisnotyetknownatthetimewhenit'sdeclarationisencountered, //fillit'splacewithzerosasaplaceholder,anditwillbelaterpopulatedwhenit'sassociated //proxyisfound process(typenameArchiveSize<SizeType, OffsetType>::ValueType{}); } voidprocess(typenameArchiveSize<SizeType, OffsetType>::Proxy&source){ //Thecurrentpositionofthestreamminusthebaseoffsetneedstobewrittentotheposition //wheretheassociated`ArchiveSize`isfound. constautocurrent=stream->tell(); assert(source.base!=nullptr); assert(source.base->value<=current); autosize=current-source.base->value; assert(size<=std::numeric_limits<SizeType>::max()); source.target->value=static_cast<SizeType>(size); //Seektotheactualpositionofthesizemarkerandwritetheabovecalculatedsize stream->seek(source.target->position); process(static_cast<SizeType>(size)); //Returntotheearliercapturedstreampositionsoprocessingcansafelyresumefromthere stream->seek(current); } voidprocess(typenameArchiveSize<SizeType, OffsetType>::Proxy&&source){ process(source); } template<typenameT,typename...Args> voidprocess(constBlob<T, Args...>&source){ usingValueType=typenameBlob<T,Args...>::value_type; if(source.size()!=0ul){ //NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) stream->write(reinterpret_cast<constchar*>(source.data()),source.size()*sizeof(ValueType)); } } template<typenameT> typenamestd::enable_if<traits::has_save_member<T>::value, void>::typeprocess(constT&source){ const_cast<T&>(source).save(*static_cast<TExtender*>(this)); } template<typenameT> typenamestd::enable_if<traits::has_serialize_member<T>::value, void>::typeprocess(constT&source){ const_cast<T&>(source).serialize(*static_cast<TExtender*>(this)); } template<typenameT> typenamestd::enable_if<traits::has_save_function<T>::value, void>::typeprocess(constT&source){ save(*static_cast<TExtender*>(this),const_cast<T&>(source)); } template<typenameT> typenamestd::enable_if<traits::has_serialize_function<T>::value, void>::typeprocess(constT&source){ serialize(*static_cast<TExtender*>(this),const_cast<T&>(source)); } template<typenameT> typenamestd::enable_if<!traits::has_save_member<T>::value&&!traits::has_serialize_member<T>::value&& !traits::has_save_function<T>::value&&!traits::has_serialize_function<T>::value, void>::typeprocess(constT&source){ Tswapped; std::memcpy(&swapped,&source,sizeof(T)); SwapTo<EByteOrder>::swap(swapped); //NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) stream->write(reinterpret_cast<char*>(&swapped),sizeof(T)); } template<typenameT,std::size_tN> voidprocess(conststd::array<T,N>&source){ processElements(source); } template<typenameT,typename...Args> voidprocess(conststd::vector<T,Args...>&source){ processSize(source.size()); processElements(source); } template<typenameT,typename...Args> voidprocess(constDynArray<T, Args...>&source){ processSize(source.size()); processElements(source); } template<typenameT,typename...Args> voidprocess(conststd::basic_string<T,Args...>&source){ processSize(source.size()); processElements(source); } template<typenameK,typenameV> voidprocess(conststd::pair<K,V>&source){ BaseArchive::dispatch(source.first); BaseArchive::dispatch(source.second); } template<typenameK,typenameV> voidprocess(conststd::tuple<K,V>&source){ BaseArchive::dispatch(std::get<0>(source)); BaseArchive::dispatch(std::get<1>(source)); } voidprocessSize(std::size_tsize){ assert(size<=std::numeric_limits<SizeType>::max()); process(static_cast<SizeType>(size)); } template<classTContainer> typenamestd::enable_if<!traits::is_batchable<TContainer>::value>::type processElements(constTContainer&source){ for(constauto&element:source){ BaseArchive::dispatch(element); } } template<classTContainer> typenamestd::enable_if<traits::is_batchable<TContainer>::value&&traits::has_wide_elements<TContainer>::value>::type processElements(constTContainer&source){ for(constauto&element:source){ BaseArchive::dispatch(element); } } template<classTContainer> typenamestd::enable_if<traits::is_batchable<TContainer>::value&&!traits::has_wide_elements<TContainer>::value>::type processElements(constTContainer&source){ usingValueType=typenameTContainer::value_type; constautosize=source.size(); if(size!=0ul){ //NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) stream->write(reinterpret_cast<constchar*>(&source[0]),size*sizeof(ValueType)); } } private: TStream*stream; }; template<classTStream,typenameTSize=std::uint32_t,typenameTOffset=TSize,EndiannessEByteOrder=Endianness::Network> classBinaryOutputArchive:publicExtendableBinaryOutputArchive<BinaryOutputArchive<TStream,TSize,TOffset,EByteOrder>, TStream, TSize, TOffset, EByteOrder>{ public: usingBaseArchive=ExtendableBinaryOutputArchive<BinaryOutputArchive, TStream, TSize, TOffset, EByteOrder>; friendArchive<BinaryOutputArchive>; public: explicitBinaryOutputArchive(TStream*stream_):BaseArchive{this,stream_}{ } private: template<typenameT> voidprocess(T&&dest){ BaseArchive::process(std::forward<T>(dest)); } }; }//namespaceterse