From: <m97...@us...> - 2012-12-29 10:20:21
|
Revision: 13102 http://openmsx.svn.sourceforge.net/openmsx/?rev=13102&view=rev Author: m9710797 Date: 2012-12-29 10:20:08 +0000 (Sat, 29 Dec 2012) Log Message: ----------- Added array_ref utility This is similar to the string_ref utility (both are modelled after utilities with the same that are proposed for the next c++ standard). An array_ref<T> refers to an array of T objects, but it does not own that array. Internally it has just a pointer to the first object in the array plus a value to indicate the length of the array. The methods getLevelStrings() and getUpdateStrings() in the CliComm class conceptually return ia collection of string-literals. An efficient way to implement this in c/c++ is to return a pointer to a c-style array, unfortunately this looses the information about the size of the array. This means that the result of these methods can't directly be used to pass to other functions that expect a range (this needs the begin and end of the array). This patch changes the return type of the two methods to array_ref<const char*>. We can use this to avoid creating an extra temporary collection to pass to the tab-completion routines. Modified Paths: -------------- openmsx/trunk/src/commands/GlobalCommandController.cc openmsx/trunk/src/events/CliComm.hh openmsx/trunk/src/events/CliConnection.cc openmsx/trunk/src/events/MessageCommand.cc openmsx/trunk/src/events/StdioMessages.cc openmsx/trunk/src/events/TclCallbackMessages.cc openmsx/trunk/src/utils/node.mk Added Paths: ----------- openmsx/trunk/src/utils/array_ref.hh Modified: openmsx/trunk/src/commands/GlobalCommandController.cc =================================================================== --- openmsx/trunk/src/commands/GlobalCommandController.cc 2012-12-29 10:19:37 UTC (rev 13101) +++ openmsx/trunk/src/commands/GlobalCommandController.cc 2012-12-29 10:20:08 UTC (rev 13102) @@ -22,6 +22,7 @@ #include "checked_cast.hh" #include "openmsx.hh" #include "memory.hh" +#include "xrange.hh" #include <cassert> #include <cstdlib> @@ -638,8 +639,8 @@ static GlobalCliComm::UpdateType getType(const string& name) { - const char* const* updateStr = CliComm::getUpdateStrings(); - for (unsigned i = 0; i < CliComm::NUM_UPDATES; ++i) { + auto updateStr = CliComm::getUpdateStrings(); + for (auto i : xrange(updateStr.size())) { if (updateStr[i] == name) { return static_cast<CliComm::UpdateType>(i); } @@ -688,13 +689,10 @@ completeString(tokens, ops); break; } - case 3: { - const char* const* updateStr = CliComm::getUpdateStrings(); - // TODO pass iterators, or pass array-reference - vector<string> types(updateStr, updateStr + CliComm::NUM_UPDATES); - completeString(tokens, types); + case 3: + completeString(tokens, CliComm::getUpdateStrings()); + break; } - } } Modified: openmsx/trunk/src/events/CliComm.hh =================================================================== --- openmsx/trunk/src/events/CliComm.hh 2012-12-29 10:19:37 UTC (rev 13101) +++ openmsx/trunk/src/events/CliComm.hh 2012-12-29 10:20:08 UTC (rev 13102) @@ -3,6 +3,7 @@ #ifndef CLICOMM_HH #define CLICOMM_HH +#include "array_ref.hh" #include "string_ref.hh" namespace openmsx { @@ -43,8 +44,12 @@ void printProgress(string_ref message); // string representations of the LogLevel and UpdateType enums - static const char* const* getLevelStrings() { return levelStr; } - static const char* const* getUpdateStrings() { return updateStr; } + static array_ref<const char*> getLevelStrings() { + return make_array_ref(levelStr); + } + static array_ref<const char*> getUpdateStrings() { + return make_array_ref(updateStr); + } protected: CliComm(); Modified: openmsx/trunk/src/events/CliConnection.cc =================================================================== --- openmsx/trunk/src/events/CliConnection.cc 2012-12-29 10:19:37 UTC (rev 13101) +++ openmsx/trunk/src/events/CliConnection.cc 2012-12-29 10:20:08 UTC (rev 13102) @@ -99,7 +99,7 @@ void CliConnection::log(CliComm::LogLevel level, string_ref message) { - const char* const* levelStr = CliComm::getLevelStrings(); + auto levelStr = CliComm::getLevelStrings(); output(StringOp::Builder() << "<log level=\"" << levelStr[level] << "\">" << XMLElement::XMLEscape(message.str()) << "</log>\n"); @@ -110,7 +110,7 @@ { if (!getUpdateEnable(type)) return; - const char* const* updateStr = CliComm::getUpdateStrings(); + auto updateStr = CliComm::getUpdateStrings(); StringOp::Builder tmp; tmp << "<update type=\"" << updateStr[type] << '\"'; if (!machine.empty()) { Modified: openmsx/trunk/src/events/MessageCommand.cc =================================================================== --- openmsx/trunk/src/events/MessageCommand.cc 2012-12-29 10:19:37 UTC (rev 13101) +++ openmsx/trunk/src/events/MessageCommand.cc 2012-12-29 10:20:08 UTC (rev 13102) @@ -3,6 +3,7 @@ #include "MessageCommand.hh" #include "CommandException.hh" #include "CliComm.hh" +#include "xrange.hh" namespace openmsx { @@ -13,8 +14,8 @@ static CliComm::LogLevel getLevel(const std::string& level) { - const char* const* levels = CliComm::getLevelStrings(); - for (int i = 0; i < CliComm::NUM_LEVELS; ++i) { + auto levels = CliComm::getLevelStrings(); + for (auto i : xrange(levels.size())) { if (level == levels[i]) { return static_cast<CliComm::LogLevel>(i); } @@ -51,9 +52,7 @@ void MessageCommand::tabCompletion(std::vector<std::string>& tokens) const { if (tokens.size() == 3) { - const char* const* levels = CliComm::getLevelStrings(); - std::vector<const char*> levelSet(levels, levels + CliComm::NUM_LEVELS); - completeString(tokens, levelSet); + completeString(tokens, CliComm::getLevelStrings()); } } Modified: openmsx/trunk/src/events/StdioMessages.cc =================================================================== --- openmsx/trunk/src/events/StdioMessages.cc 2012-12-29 10:19:37 UTC (rev 13101) +++ openmsx/trunk/src/events/StdioMessages.cc 2012-12-29 10:20:08 UTC (rev 13102) @@ -9,7 +9,7 @@ void StdioMessages::log(CliComm::LogLevel level, string_ref message) { - const char* const* levelStr = CliComm::getLevelStrings(); + auto levelStr = CliComm::getLevelStrings(); ((level == CliComm::INFO) ? std::cout : std::cerr) << levelStr[level] << ": " << message << std::endl; Modified: openmsx/trunk/src/events/TclCallbackMessages.cc =================================================================== --- openmsx/trunk/src/events/TclCallbackMessages.cc 2012-12-29 10:19:37 UTC (rev 13101) +++ openmsx/trunk/src/events/TclCallbackMessages.cc 2012-12-29 10:20:08 UTC (rev 13102) @@ -28,7 +28,7 @@ void TclCallbackMessages::log(CliComm::LogLevel level, string_ref message) { - const char* const* levelStr = CliComm::getLevelStrings(); + auto levelStr = CliComm::getLevelStrings(); messageCallback->execute(message, levelStr[level]); } Added: openmsx/trunk/src/utils/array_ref.hh =================================================================== --- openmsx/trunk/src/utils/array_ref.hh (rev 0) +++ openmsx/trunk/src/utils/array_ref.hh 2012-12-29 10:20:08 UTC (rev 13102) @@ -0,0 +1,117 @@ +#ifndef ARRAY_REF_HH +#define ARRAY_REF_HH + +#include <algorithm> +#include <iterator> +#include <vector> +#include <cassert> +#include <cstddef> + +/** This class implements a subset of the proposal for std::array_ref + * (proposed for the next c++ standard (c++1y)). + * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3334.html#classstd_1_1array__ref + * + * It has an interface that is close to std::vector, but it does not own the + * memory of the array. Basically it's just a wrapper around a pointer plus + * length. + */ +template<typename T> +class array_ref +{ +public: + // types + typedef T value_type; + typedef const T* pointer; + typedef const T& reference; + typedef const T& const_reference; + typedef const T* const_iterator; + typedef const_iterator iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + typedef const_reverse_iterator reverse_iterator; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + // construct/copy/assign + array_ref() + : dat(nullptr), siz(0) {} + array_ref(const array_ref& r) + : dat(r.data()), siz(r.size()) {} + array_ref(const T* array, size_t length) + : dat(array), siz(length) {} + array_ref(const std::vector<T>& v) + : dat(v.data()), siz(v.size()) {} + template<size_t N> array_ref(const T(&a)[N]) + : dat(a), siz(N) {} + + array_ref& operator=(const array_ref& rhs) { + dat = rhs.data(); + siz = rhs.size(); + return *this; + } + + // iterators + const_iterator begin() const { return dat; } + const_iterator end() const { return dat + siz; } + const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } + const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } + + // capacity + size_type size() const { return siz; } + bool empty() const { return siz == 0; } + + // element access + const T& operator[](size_t i) const { + assert(i < siz); + return dat[i]; + } + const T& front() const { return (*this)[0]; } + const T& back() const { return (*this)[siz - 1]; } + const T* data() const { return dat; } + + // mutators + void clear() { siz = 0; } // no need to change 'dat' + void remove_prefix(size_type n) { + if (n <= siz) { + dat += n; + siz -= n; + } else { + clear(); + } + } + void remove_suffix(size_type n) { + if (n <= siz) { + siz -= n; + } else { + clear(); + } + } + void pop_back() { remove_suffix(1); } + void pop_front() { remove_prefix(1); } + + array_ref substr(size_type pos, size_type n = size_type(-1)) const { + if (pos >= siz) return array_ref(); + return array_ref(dat + pos, std::min(n, siz - pos)); + } + +private: + const T* dat; + size_type siz; +}; + +// deducing constructor wrappers +template<typename T> inline array_ref<T> make_array_ref(const T* array, size_t length) +{ + return array_ref<T>(array, length); +} + +template<typename T, size_t N> inline array_ref<T> make_array_ref(const T(&a)[N]) +{ + return array_ref<T>(a); +} + +template<typename T> inline array_ref<T> make_array_ref(const std::vector<T>& v) +{ + return array_ref<T>(v); +} + +#endif Modified: openmsx/trunk/src/utils/node.mk =================================================================== --- openmsx/trunk/src/utils/node.mk 2012-12-29 10:19:37 UTC (rev 13101) +++ openmsx/trunk/src/utils/node.mk 2012-12-29 10:20:08 UTC (rev 13102) @@ -30,6 +30,7 @@ checked_cast \ endian \ alignof \ + array_ref \ likely \ inline \ memory \ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |