//--------------------------------------------------------------------*- C++ -*- // CLING - the C++ LLVM-based InterpreterG :) // author: Boris Perovic // author: Danilo Piparo // // This file is dual-licensed: you can choose to license it under the University // of Illinois Open Source License or the GNU Lesser General Public License. See // LICENSE.TXT for details. //------------------------------------------------------------------------------ #ifndef CLING_RUNTIME_PRINT_VALUE_H #define CLING_RUNTIME_PRINT_VALUE_H #if !defined(__CLING__) #error "This file must not be included by compiled programs." #endif #include #include #include #include namespace cling { class Value; // General fallback - prints the address std::string printValue(const void *ptr); // Fallback for e.g. vector's bit iterator: template ::value>::type> inline std::string printValue(const T& val) { return "{not representable}"; } // void pointer std::string printValue(const void **ptr); // Bool std::string printValue(const bool *val); // Chars std::string printValue(const char *val); std::string printValue(const signed char *val); std::string printValue(const unsigned char *val); std::string printValue(const char16_t *val); std::string printValue(const char32_t *val); std::string printValue(const wchar_t *val); // Ints std::string printValue(const short *val); std::string printValue(const unsigned short *val); std::string printValue(const int *val); std::string printValue(const unsigned int *val); std::string printValue(const long *val); std::string printValue(const unsigned long *val); std::string printValue(const long long *val); std::string printValue(const unsigned long long *val); // Reals std::string printValue(const float *val); std::string printValue(const double *val); std::string printValue(const long double *val); // Char pointers std::string printValue(const char *const *val); std::string printValue(const char **val); // std::string std::string printValue(const std::string *val); std::string printValue(const std::wstring *val); std::string printValue(const std::u16string *val); std::string printValue(const std::u32string *val); // constant unicode strings, i.e. u"String" template std::string toUTF8(const T* const Src, size_t N, const char Prefix = 0); template inline std::string printValue(char16_t const (*val)[N]) { return toUTF8(reinterpret_cast(val), N, 'u'); } template inline std::string printValue(char32_t const (*val)[N]) { return toUTF8(reinterpret_cast(val), N, 'U'); } template inline std::string printValue(wchar_t const (*val)[N]) { return toUTF8(reinterpret_cast(val), N, 'L'); } template inline std::string printValue(char const (*val)[N]) { return toUTF8(reinterpret_cast(val), N, 1); } // cling::Value std::string printValue(const Value *value); namespace valuePrinterInternal { extern const char* const kEmptyCollection; } // Collections internal namespace collectionPrinterInternal { // Forward declaration, so recursion of containers possible. template std::string printValue(const T* V, const void* = 0); template inline std::string printValue(const T& V, typename std::enable_if< std::is_pointer::value>::type* = 0) { return printValue(&V); } template inline std::string printValue(const std::pair* V, const void* AsMap = 0) { if (AsMap) return printValue(&V->first) + " => " + printValue(&V->second); return "{" + printValue(&V->first) + " , " + printValue(&V->second) + "}"; } // For std::vector elements inline std::string printValue(const bool& B, const void* = 0) { return cling::printValue(&B); } struct TypeTest { template static constexpr const void* isMap(const T* M, const typename T::mapped_type* V = 0) { return M; } static constexpr const void* isMap(const void* M) { return nullptr; } }; // vector, set, deque etc. template inline auto printValue_impl( const CollectionType* obj, typename std::enable_if< std::is_referencebegin()))>::value>::type* = 0) -> decltype(++(obj->begin()), obj->end(), std::string()) { auto iter = obj->begin(), iterEnd = obj->end(); if (iter == iterEnd) return valuePrinterInternal::kEmptyCollection; const void* M = TypeTest::isMap(obj); std::string str("{ "); str += printValue(&(*iter), M); while (++iter != iterEnd) { str += ", "; str += printValue(&(*iter), M); } return str + " }"; } // As above, but without ability to take address of elements. template inline auto printValue_impl( const CollectionType* obj, typename std::enable_if< !std::is_referencebegin()))>::value>::type* = 0) -> decltype(++(obj->begin()), obj->end(), std::string()) { auto iter = obj->begin(), iterEnd = obj->end(); if (iter == iterEnd) return valuePrinterInternal::kEmptyCollection; std::string str("{ "); str += printValue(*iter); while (++iter != iterEnd) { str += ", "; str += printValue(*iter); } return str + " }"; } } // Collections template inline auto printValue(const CollectionType *obj) -> decltype(collectionPrinterInternal::printValue_impl(obj), std::string()) { return collectionPrinterInternal::printValue_impl(obj); } // Arrays template inline std::string printValue(const T (*obj)[N]) { if (N == 0) return valuePrinterInternal::kEmptyCollection; std::string str = "{ "; str += printValue(*obj + 0); for (size_t i = 1; i < N; ++i) { str += ", "; str += printValue(*obj + i); } return str + " }"; } // Tuples template inline std::string printValue(std::tuple *); namespace collectionPrinterInternal { // We loop at compile time from element 0 to element TUPLE_SIZE - 1 // of the tuple. The running index is N which has as initial value // TUPLE_SIZE. We can therefore stop the iteration and account for the // empty tuple case with one single specialisation. template (), std::size_t TUPLE_SIZE = std::tuple_size()> struct tuplePrinter { static std::string print(TUPLE *t) { constexpr std::size_t elementNumber = TUPLE_SIZE - N; using Element_t = decltype(std::get(*t)); std::string ret; if (elementNumber) ret += ", "; ret += cling::printValue(&std::get(*t)); // If N+1 is not smaller than the size of the tuple, // reroute the call to the printing function to the // no-op specialisation to stop recursion. constexpr std::size_t Nm1 = N - 1; ret += tuplePrinter::print((TUPLE *)t); return ret; } }; // Special case: no op if last element reached or empty tuple template struct tuplePrinter { static std::string print(TUPLE *t) {return "";} }; template inline std::string tuplePairPrintValue(T *val) { std::string ret("{ "); ret += collectionPrinterInternal::tuplePrinter::print(val); ret += " }"; return ret; } } template inline std::string printValue(std::tuple *val) { using T = std::tuple; if (std::tuple_size::value == 0) return valuePrinterInternal::kEmptyCollection; return collectionPrinterInternal::tuplePairPrintValue(val); } template inline std::string printValue(std::pair *val) { using T = std::pair; return collectionPrinterInternal::tuplePairPrintValue(val); } namespace collectionPrinterInternal { // Keep this last to allow picking up all specializations above. template std::string printValue(const T* V, const void*) { return cling::printValue(V); } } // unique_ptr: template inline std::string printValue(std::unique_ptr *val) { auto ptr = val->get(); // printValue dereference its argument. use cast to 'const void**' to get // the same printout as a regular pointer. return "std::unique_ptr -> " + printValue((const void**)&ptr); } // shared_ptr: template inline std::string printValue(std::shared_ptr *val) { auto ptr = val->get(); // printValue dereference its argument. use cast to 'const void**' to get // the same printout as a regular pointer. return "std::shared_ptr -> " + printValue((const void**)&ptr); } // weak_ptr: template inline std::string printValue(std::weak_ptr *val) { auto ptr = val->lock().get(); // printValue dereference its argument. use cast to 'const void**' to get // the same printout as a regular pointer. return "std::weak_ptr -> " + printValue((const void**)&ptr); } } #endif