// -*- C++ -*- // // Copyright (c) 2019 Wolfgang 'datenwolf' Draxinger // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. #pragma once #ifndef DWU__OPERATORS__ #define DWU__OPERATORS__ 1 /* === Implementation Notes === == On the use of explicitly implemented min instead of std::min == Within the operator functions that work on two containers, the output length is truncated to the shorter of the two containers by an explicitly written out min-comparison, like this: auto const lsz = l.size(); auto const rsz = r.size(); Cl v( (lsz < rsz) ? lsz : rsz ); This is used instead of std::min defined for two reasons: 1. It avoids inclusion of a header. Although is rather lightweight, the extra compile time is measureable. 2. std::min expects both inputs to be strictly of the same type. This however makes it impossible to do mixed container operation with containers that use a different size type, which however is something we want to support. **/ namespace dwu { namespace operators { // same container, same type #define DWU_OPERATORS(O) \ template class C, typename T, typename A> \ C operator O (C const &l, T const &r) { \ C v(l.size()); \ auto vi = v.begin(); auto li = l.begin(); \ while( vi != v.end() ){ \ *vi++ = *li++ O r; \ } \ return v; \ } \ template class C, typename T, typename A> \ C operator O (T const &l, C const &r) { \ C v(r.size()); \ auto vi = v.begin(); auto ri = r.begin(); \ while( vi != v.end() ){ \ *vi++ = l O *ri++; \ } \ return v; \ } \ template class C, typename T, typename A> \ C operator O (C const &l, C const &r) { \ auto const lsz = l.size(); auto const rsz = r.size(); \ C v( (lsz < rsz) ? lsz : rsz ); \ auto vi = v.begin(); auto li = l.begin(); auto ri = r.begin(); \ while( vi != v.end() ){ \ *vi++ = *li++ O *ri++; \ } \ return v; \ } \ template class C, typename T, typename A> \ C& operator O##= (C &l, T const &r){ \ for(auto &x:l){ x O##= r; } \ return l; \ } \ template class C, typename T, typename A> \ C& operator O##= (C &l, C const &r){ \ auto li = l.begin(); auto ri = r.begin(); \ while( li != l.end() && ri != r.end() ){ \ *li++ O##= *ri++; \ } \ return l; \ } namespace arithmetic { DWU_OPERATORS(+) DWU_OPERATORS(-) DWU_OPERATORS(*) DWU_OPERATORS(/) DWU_OPERATORS(%) } namespace bitwise { DWU_OPERATORS(^) DWU_OPERATORS(&) DWU_OPERATORS(|) } namespace shift { DWU_OPERATORS(>>) DWU_OPERATORS(<<) } #undef DWU_OPERATORS } namespace operators_xt { // same container, mixed type #define DWU_OPERATORS_XT(O) \ template< \ template class C, \ typename Tl, typename Al, \ typename Tr > \ C operator O (C const &l, Tr const &r) { \ C v(l.size()); \ auto vi = v.begin(); auto li = l.begin(); \ while( vi != v.end() ){ \ *vi++ = *li++ O r; \ } \ return v; \ } \ template< \ template class C, \ typename Tl, \ typename Tr, typename Ar > \ C operator O (Tl const &l, C const &r) { \ C v(r.size()); \ auto vi = v.begin(); auto ri = r.begin(); \ while( vi != v.end() ){ \ *vi++ = l O *ri++; \ } \ return v; \ } \ template< \ template class C, \ typename Tl, typename Al, \ typename Tr, typename Ar > \ C operator O (C const &l, C const &r) { \ auto const lsz = l.size(); auto const rsz = r.size(); \ C v( (lsz < rsz) ? lsz : rsz ); \ auto vi = v.begin(); auto li = l.begin(); auto ri = r.begin(); \ while( vi != v.end() ){ \ *vi++ = *li++ O *ri++; \ } \ return v; \ } \ template< \ template class C, \ typename Tl, typename Al, \ typename Tr > \ C& operator O##= (C &l, Tr const &r){ \ for(auto &x:l){ x O##= r; } \ return l; \ } namespace arithmetic { DWU_OPERATORS_XT(+) DWU_OPERATORS_XT(-) DWU_OPERATORS_XT(*) DWU_OPERATORS_XT(/) DWU_OPERATORS_XT(%) } namespace bitwise { DWU_OPERATORS_XT(^) DWU_OPERATORS_XT(&) DWU_OPERATORS_XT(|) } namespace shift { DWU_OPERATORS_XT(>>) DWU_OPERATORS_XT(<<) } #undef DWU_OPERATORS_XT } namespace operators_xc { // mixed container, same type #define DWU_OPERATORS_XC(O) \ template< \ template class Cl, \ template class Cr, \ typename T, typename A > \ Cl operator O (Cl const &l, Cr const &r) { \ auto const lsz = l.size(); auto const rsz = r.size(); \ Cl v( (lsz < rsz) ? lsz : rsz ); \ auto vi = v.begin(); auto li = l.begin(); auto ri = r.begin(); \ while( vi != v.end() ){ \ *vi++ = *li++ O *ri++; \ } \ return v; \ } \ template< \ template class Cl, \ template class Cr, \ typename T, typename A > \ Cl& operator O##= (Cl &l, Cr const &r){ \ auto li = l.begin(); auto ri = r.begin(); \ while( li != l.end() && ri != r.end() ){ \ *li++ O##= *ri++; \ } \ return l; \ } namespace arithmetic { DWU_OPERATORS_XC(+) DWU_OPERATORS_XC(-) DWU_OPERATORS_XC(*) DWU_OPERATORS_XC(/) DWU_OPERATORS_XC(%) } namespace bitwise { DWU_OPERATORS_XC(^) DWU_OPERATORS_XC(&) DWU_OPERATORS_XC(|) } namespace shift { DWU_OPERATORS_XC(>>) DWU_OPERATORS_XC(<<) } #undef DWU_OPERATORS_XC } namespace operators_xcxt { // mixed container, mixed type #define DWU_OPERATORS_XCXT(O) \ template< \ template class Cl, \ template class Cr, \ typename Tl, typename Al, \ typename Tr, typename Ar > \ Cl operator O (Cl const &l, Cr const &r) { \ auto const lsz = l.size(); auto const rsz = r.size(); \ Cl v( (lsz < rsz) ? lsz : rsz ); \ auto vi = v.begin(); auto li = l.begin(); auto ri = r.begin(); \ while( vi != v.end() ){ \ *vi++ = *li++ O *ri++; \ } \ return v; \ } \ template< \ template class Cl, \ template class Cr, \ typename Tl, typename Al, \ typename Tr, typename Ar > \ Cl& operator O##= (Cl &l, Cr const &r){ \ auto li = l.begin(); auto ri = r.begin(); \ while( li != l.end() && ri != r.end() ){ \ *li++ O##= *ri++; \ } \ return l; \ } namespace arithmetic { DWU_OPERATORS_XCXT(+) DWU_OPERATORS_XCXT(-) DWU_OPERATORS_XCXT(*) DWU_OPERATORS_XCXT(/) DWU_OPERATORS_XCXT(%) } namespace bitwise { DWU_OPERATORS_XCXT(^) DWU_OPERATORS_XCXT(&) DWU_OPERATORS_XCXT(|) } namespace shift { DWU_OPERATORS_XCXT(>>) DWU_OPERATORS_XCXT(<<) } #undef DWU_OPERATORS_XCXT } } #endif/*DWU__OPERATORS__*/