Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:54:48

0001 //----------------------------------*-C++-*----------------------------------//
0002 // Copyright 2021-2024 UT-Battelle, LLC, and other Celeritas developers.
0003 // See the top-level COPYRIGHT file for details.
0004 // SPDX-License-Identifier: (Apache-2.0 OR MIT)
0005 //---------------------------------------------------------------------------//
0006 //! \file corecel/io/Repr.hh
0007 //---------------------------------------------------------------------------//
0008 #pragma once
0009 
0010 #include <iomanip>
0011 #include <sstream>
0012 #include <string>
0013 #include <string_view>
0014 #include <utility>
0015 #include <vector>
0016 
0017 #include "corecel/OpaqueId.hh"
0018 #include "corecel/cont/Array.hh"
0019 #include "corecel/cont/Span.hh"
0020 #include "corecel/data/Collection.hh"
0021 #include "corecel/math/Quantity.hh"
0022 
0023 #include "Join.hh"
0024 
0025 #include "detail/ReprImpl.hh"
0026 
0027 namespace celeritas
0028 {
0029 //---------------------------------------------------------------------------//
0030 /*!
0031  * Return a streamable object that prints out a C++-style.
0032  *
0033  * Example:
0034  * \code
0035   std::cout << repr(my_vec) << std::endl;
0036   \endcode
0037 
0038  * The 'name' argument defaults to null (just printing the value); if a string
0039  * is given a full variable declaration such as `std::string foo{"bar"}` will
0040  * be printed. If the name is empty, an anonymous value `std::string{"bar"}`
0041  * will be printed.
0042  */
0043 template<class T>
0044 detail::Repr<T> repr(T const& obj, char const* name = nullptr)
0045 {
0046     return {obj, name};
0047 }
0048 
0049 //---------------------------------------------------------------------------//
0050 /*!
0051  * Traits for writing an object for diagnostic or testing output.
0052  *
0053  * The "streamable" traits usually write so that the object can be injected
0054  * into test code.  The default tries to use whatever ostream operator is
0055  * available.
0056  * Other overrides are provided for collections, characters, and more?
0057  */
0058 template<class T>
0059 struct ReprTraits
0060 {
0061     static void print_type(std::ostream& os, char const* name = nullptr)
0062     {
0063         detail::print_simple_type(os, "UNKNOWN", name);
0064     }
0065     static void init(std::ostream&) {}
0066     static void print_value(std::ostream& os, T const& value) { os << value; }
0067 };
0068 
0069 template<>
0070 struct ReprTraits<float>
0071 {
0072     static void print_type(std::ostream& os, char const* name = nullptr)
0073     {
0074         detail::print_simple_type(os, "float", name);
0075     }
0076     static void init(std::ostream& os) { os.precision(7); }
0077     static void print_value(std::ostream& os, float value)
0078     {
0079         os << value << 'f';
0080     }
0081 };
0082 
0083 template<>
0084 struct ReprTraits<double>
0085 {
0086     static void print_type(std::ostream& os, char const* name = nullptr)
0087     {
0088         detail::print_simple_type(os, "double", name);
0089     }
0090     static void init(std::ostream& os) { os.precision(14); }
0091     static void print_value(std::ostream& os, double value) { os << value; }
0092 };
0093 
0094 template<>
0095 struct ReprTraits<char>
0096 {
0097     static void print_type(std::ostream& os, char const* name = nullptr)
0098     {
0099         detail::print_simple_type(os, "char", name);
0100     }
0101     static void init(std::ostream&) {}
0102     static void print_value(std::ostream& os, char value)
0103     {
0104         os << '\'';
0105         detail::repr_char(os, value);
0106         os << '\'';
0107     }
0108 };
0109 
0110 template<>
0111 struct ReprTraits<unsigned char>
0112 {
0113     static void print_type(std::ostream& os, char const* name = nullptr)
0114     {
0115         detail::print_simple_type(os, "unsigned char", name);
0116     }
0117     static void init(std::ostream& os) { os << std::setfill('0') << std::hex; }
0118     static void print_value(std::ostream& os, unsigned char value)
0119     {
0120         os << "'\\x" << detail::char_to_hex_string(value) << '\'';
0121     }
0122 };
0123 
0124 template<>
0125 struct ReprTraits<bool>
0126 {
0127     static void print_type(std::ostream& os, char const* name = nullptr)
0128     {
0129         detail::print_simple_type(os, "bool", name);
0130     }
0131     static void init(std::ostream& os) { os << std::boolalpha; }
0132     static void print_value(std::ostream& os, bool value) { os << value; }
0133 };
0134 
0135 template<>
0136 struct ReprTraits<int>
0137 {
0138     static void print_type(std::ostream& os, char const* name = nullptr)
0139     {
0140         detail::print_simple_type(os, "int", name);
0141     }
0142     static void init(std::ostream&) {}
0143     static void print_value(std::ostream& os, int value) { os << value; }
0144 };
0145 
0146 template<>
0147 struct ReprTraits<unsigned int>
0148 {
0149     static void print_type(std::ostream& os, char const* name = nullptr)
0150     {
0151         detail::print_simple_type(os, "unsigned int", name);
0152     }
0153     static void init(std::ostream&) {}
0154     static void print_value(std::ostream& os, unsigned int value)
0155     {
0156         os << value << 'u';
0157     }
0158 };
0159 
0160 template<>
0161 struct ReprTraits<long>
0162 {
0163     static void print_type(std::ostream& os, char const* name = nullptr)
0164     {
0165         detail::print_simple_type(os, "long", name);
0166     }
0167     static void init(std::ostream&) {}
0168     static void print_value(std::ostream& os, long value)
0169     {
0170         os << value << 'l';
0171     }
0172 };
0173 
0174 template<>
0175 struct ReprTraits<unsigned long>
0176 {
0177     static void print_type(std::ostream& os, char const* name = nullptr)
0178     {
0179         detail::print_simple_type(os, "unsigned long", name);
0180     }
0181     static void init(std::ostream&) {}
0182     static void print_value(std::ostream& os, unsigned long value)
0183     {
0184         os << value << "ul";
0185     }
0186 };
0187 
0188 template<>
0189 struct ReprTraits<long long>
0190 {
0191     static void print_type(std::ostream& os, char const* name = nullptr)
0192     {
0193         detail::print_simple_type(os, "long long", name);
0194     }
0195     static void init(std::ostream&) {}
0196     static void print_value(std::ostream& os, long long value)
0197     {
0198         os << value << "ll";
0199     }
0200 };
0201 
0202 template<>
0203 struct ReprTraits<unsigned long long>
0204 {
0205     static void print_type(std::ostream& os, char const* name = nullptr)
0206     {
0207         detail::print_simple_type(os, "unsigned long long", name);
0208     }
0209     static void init(std::ostream&) {}
0210     static void print_value(std::ostream& os, unsigned long long value)
0211     {
0212         os << value << "ull";
0213     }
0214 };
0215 
0216 template<>
0217 struct ReprTraits<std::string_view>
0218 {
0219     static void print_type(std::ostream& os, char const* name = nullptr)
0220     {
0221         detail::print_simple_type(os, "std::string_view", name);
0222     }
0223 
0224     static void init(std::ostream&) {}
0225     static void print_value(std::ostream& os, std::string_view value)
0226     {
0227         using ssize = std::streamsize;
0228         ssize width = os.width();
0229         os.width(
0230             std::max(width - static_cast<ssize>(value.size()) - 2, ssize{0}));
0231 
0232         if (value.size() > 70)
0233         {
0234             // Print long literal string on one line
0235             os << "R\"(" << value << ")\"";
0236             return;
0237         }
0238 
0239         os << '"';
0240         for (char c : value)
0241         {
0242             if (c == '\"')
0243             {
0244                 os << '\\';
0245             }
0246             detail::repr_char(os, c);
0247         }
0248         os << '"';
0249     }
0250 };
0251 
0252 template<>
0253 struct ReprTraits<std::string>
0254 {
0255     using value_type = std::string::value_type;
0256 
0257     static void print_type(std::ostream& os, char const* name = nullptr)
0258     {
0259         detail::print_simple_type(os, "std::string", name);
0260     }
0261 
0262     static void init(std::ostream&) {}
0263     static void print_value(std::ostream& os, std::string const& value)
0264     {
0265         ReprTraits<std::string_view>::print_value(os, value);
0266     }
0267 };
0268 
0269 template<>
0270 struct ReprTraits<char*>
0271 {
0272     using value_type = char;
0273 
0274     static void print_type(std::ostream& os, char const* name = nullptr)
0275     {
0276         detail::print_simple_type(os, "char const*", name);
0277     }
0278 
0279     static void init(std::ostream&) {}
0280 
0281     static void print_value(std::ostream& os, char const* value)
0282     {
0283         if (value)
0284         {
0285             ReprTraits<std::string_view>::print_value(os, value);
0286         }
0287         else
0288         {
0289             os << "nullptr";
0290         }
0291     }
0292 };
0293 
0294 template<std::size_t N>
0295 struct ReprTraits<char[N]> : ReprTraits<char*>
0296 {
0297 };
0298 
0299 template<>
0300 struct ReprTraits<char const*> : ReprTraits<char*>
0301 {
0302 };
0303 
0304 //! Specialization for printing std::pairs
0305 template<class T1, class T2>
0306 struct ReprTraits<std::pair<T1, T2>>
0307 {
0308     using RT1 = ReprTraits<T1>;
0309     using RT2 = ReprTraits<T2>;
0310 
0311     static void print_type(std::ostream& os, char const* name = nullptr)
0312     {
0313         os << "std::pair<";
0314         RT1::print_type(os);
0315         os << ',';
0316         RT2::print_type(os);
0317         os << '>';
0318         if (name)
0319         {
0320             os << ' ' << name;
0321         }
0322     }
0323 
0324     static void init(std::ostream& os)
0325     {
0326         RT1::init(os);
0327         RT2::init(os);
0328     }
0329 
0330     static void print_value(std::ostream& os, std::pair<T1, T2> const& value)
0331     {
0332         os << '{';
0333         RT1::print_value(os, value.first);
0334         os << ',';
0335         RT2::print_value(os, value.second);
0336         os << '}';
0337     }
0338 };
0339 
0340 //! Specialization for OpaqueId
0341 template<class V, class S>
0342 struct ReprTraits<OpaqueId<V, S>>
0343 {
0344     using RT = ReprTraits<S>;
0345 
0346     static void print_type(std::ostream& os, char const* name = nullptr)
0347     {
0348         os << "OpaqueID<?>";
0349         if (name)
0350         {
0351             os << ' ' << name;
0352         }
0353     }
0354 
0355     static void init(std::ostream& os) { RT::init(os); }
0356 
0357     static void print_value(std::ostream& os, OpaqueId<V, S> const& value)
0358     {
0359         os << '{';
0360         if (value)
0361         {
0362             RT::print_value(os, value.unchecked_get());
0363         }
0364         os << '}';
0365     }
0366 };
0367 
0368 //! Specialization for Quantity
0369 template<class U, class V>
0370 struct ReprTraits<Quantity<U, V>>
0371 {
0372     using RT = ReprTraits<V>;
0373 
0374     static void print_type(std::ostream& os, char const* name = nullptr)
0375     {
0376         os << "Quantity<?,?>";
0377         if (name)
0378         {
0379             os << ' ' << name;
0380         }
0381     }
0382 
0383     static void init(std::ostream& os) { RT::init(os); }
0384 
0385     static void print_value(std::ostream& os, Quantity<U, V> const& q)
0386     {
0387         os << '{';
0388         RT::print_value(os, q.value());
0389         os << '}';
0390     }
0391 };
0392 
0393 //---------------------------------------------------------------------------//
0394 // CONTAINER TRAITS
0395 //---------------------------------------------------------------------------//
0396 template<class Container>
0397 struct ContTraits
0398 {
0399     using size_type = typename Container::size_type;
0400     using value_type = std::decay_t<typename Container::value_type>;
0401 };
0402 
0403 template<class T, std::size_t N>
0404 struct ContTraits<T[N]>
0405 {
0406     using size_type = std::size_t;
0407     using value_type = std::decay_t<T>;
0408 };
0409 
0410 /*!
0411  * Get a string representation of a container of type T.
0412  */
0413 template<class Container>
0414 struct ContainerReprTraits
0415 {
0416     using value_type = typename ContTraits<Container>::value_type;
0417     using RT = ReprTraits<value_type>;
0418 
0419     static void init(std::ostream& os) { RT::init(os); }
0420 
0421     static void print_value(std::ostream& os, Container const& data)
0422     {
0423         os << '{'
0424            << join_stream(
0425                   std::begin(data), std::end(data), ", ", RT::print_value);
0426         if (std::size(data) > 8)
0427         {
0428             // Add a trailing ',' to long outputs to help clang-format
0429             os << ',';
0430         }
0431         os << '}';
0432     }
0433 };
0434 
0435 template<class T, class A>
0436 struct ReprTraits<std::vector<T, A>>
0437     : public ContainerReprTraits<std::vector<T, A>>
0438 {
0439     using value_type = std::decay_t<T>;
0440 
0441     static void print_type(std::ostream& os, char const* name = nullptr)
0442     {
0443         detail::print_container_type<value_type>(os, "std::vector", name);
0444     }
0445 };
0446 
0447 template<class T, size_type N>
0448 struct ReprTraits<Array<T, N>> : public ContainerReprTraits<Array<T, N>>
0449 {
0450     using value_type = std::decay_t<T>;
0451 
0452     static void print_type(std::ostream& os, char const* name = nullptr)
0453     {
0454         os << "Array<";
0455         ReprTraits<value_type>::print_type(os);
0456         os << ',' << N << '>';
0457         if (name)
0458         {
0459             os << ' ' << name;
0460         }
0461     }
0462 };
0463 
0464 template<class T, std::size_t N>
0465 struct ReprTraits<T[N]> : public ContainerReprTraits<T[N]>
0466 {
0467     using value_type = std::decay_t<T>;
0468 
0469     static void print_type(std::ostream& os, char const* name = nullptr)
0470     {
0471         os << "Array<";
0472         ReprTraits<value_type>::print_type(os);
0473         os << ',' << N << '>';
0474         if (name)
0475         {
0476             os << ' ' << name;
0477         }
0478     }
0479 };
0480 
0481 template<class T, std::size_t N>
0482 struct ReprTraits<Span<T, N>> : public ContainerReprTraits<Span<T, N>>
0483 {
0484     using value_type = std::decay_t<T>;
0485 
0486     static void print_type(std::ostream& os, char const* name = nullptr)
0487     {
0488         detail::print_container_type<value_type>(os, "Span", name);
0489     }
0490 };
0491 
0492 //! Print collection host data
0493 template<class T, Ownership W, class I>
0494 struct ReprTraits<Collection<T, W, MemSpace::host, I>>
0495 {
0496     using ContainerT = Collection<T, W, MemSpace::host, I>;
0497     using value_type = typename ContainerT::value_type;
0498     using RT = ReprTraits<value_type>;
0499 
0500     static void init(std::ostream& os) { RT::init(os); }
0501 
0502     static void print_value(std::ostream& os, ContainerT const& data)
0503     {
0504         auto view = data[typename ContainerT::AllItemsT{}];
0505         os << '{'
0506            << join_stream(
0507                   std::begin(view), std::end(view), ", ", RT::print_value)
0508            << '}';
0509     }
0510 
0511     static void print_type(std::ostream& os, char const* name = nullptr)
0512     {
0513         detail::print_container_type<value_type>(os, "Collection", name);
0514     }
0515 };
0516 
0517 //! Print placeholder for device data
0518 template<class T, Ownership W, class I>
0519 struct ReprTraits<Collection<T, W, MemSpace::device, I>>
0520 {
0521     using ContainerT = Collection<T, W, MemSpace::device, I>;
0522     using value_type = typename ContainerT::value_type;
0523 
0524     static void init(std::ostream&) {}
0525 
0526     static void print_value(std::ostream& os, ContainerT const& data)
0527     {
0528         auto view = data[typename ContainerT::AllItemsT{}];
0529         os << "<device collection, size=" << data.size() << '>';
0530     }
0531 
0532     static void print_type(std::ostream& os, char const* name = nullptr)
0533     {
0534         detail::print_container_type<value_type>(os, "Collection", name);
0535     }
0536 };
0537 
0538 //---------------------------------------------------------------------------//
0539 }  // namespace celeritas