diff --git a/array.h b/array.h index 8d2191a..60e4efa 100644 --- a/array.h +++ b/array.h @@ -1,48 +1,71 @@ #pragma once + #include #include "common.h" #include "random.h" -#include "named_arguments.h" +#include "repr.h" namespace impl { typedef std::pair Range; template -class GenericArray : public std::vector { +class GenericArray : public Repr>, public std::vector { public: typedef std::vector Base; + using Base::Base; + GenericArray() {} GenericArray(const GenericArray&) = default; GenericArray& operator=(const GenericArray&) = default; + GenericArray(GenericArray&&) = default; + GenericArray& operator=(GenericArray&&) = default; + + ~GenericArray() {} + /* implicit */ GenericArray(const Base& base) : Base(base) { } - template - GenericArray(Args... args) : - Base(args...) - { } - // syntaxic sugar for the god of C++ - size_t size() const { - return Base::size(); - } - T& at(size_t idx) { - return Base::at(idx); - } - const T& at(size_t idx) const { - return Base::at(idx); - } + // TODO(ifsmirnov): 'use' all methods and make inheritance private + using Base::at; + using Base::operator[]; + using Base::size; + using Base::begin; + using Base::end; static GenericArray random(size_t size, T max); static GenericArray random(size_t size, T min, T max); static GenericArray random(const Range& size, T max); static GenericArray random(const Range& size, T min, T max); + static GenericArray id(size_t size, T start = T{}); + GenericArray& shuffle(); + GenericArray shuffled() const; + GenericArray& reverse(); + GenericArray reversed() const; + + GenericArray& sort(); + GenericArray sorted() const; + + // TODO(ifsmirnov): think about naming + GenericArray& add(T value); + GenericArray added(T value) const; + + template + GenericArray subseq(const std::vector& indices) const; + + template + GenericArray subseq( + const std::initializer_list& indices) const; + + const T& choice() const; + GenericArray choice(size_t count) const; + GenericArray choiceWithRepetition(size_t count) const; }; template @@ -65,18 +88,38 @@ GenericArray GenericArray::random(size_t size, T min, T max) { template GenericArray GenericArray::random(const Range& size, T max) { - return GenericArray::random(rnd.next(size.first, size.second), max); + return random(rnd.next(size.first, size.second), max); } template GenericArray GenericArray::random(const Range& size, T min, T max) { - return GenericArray::random(rnd.next(size.first, size.second), min, max); + return random(rnd.next(size.first, size.second), min, max); } template -GenericArray& GenericArray::reverse() { - std::reverse(this->begin(), this->end()); - return *this; +auto genericArrayIdHelper(size_t size, T start) + -> typename std::enable_if< + std::is_integral::value, GenericArray + >::type +{ + GenericArray result(size); + std::iota(result.begin(), result.end(), start); + return result; +} + +template +auto genericArrayIdHelper(size_t size, const T& start) + -> typename std::enable_if< + !std::is_integral::value, GenericArray + >::type +{ + ensure("Cannot take GenericArray::id() when T is non-integral"); + return {}; +} + +template +GenericArray GenericArray::id(size_t size, T start) { + return genericArrayIdHelper(size, start); } template @@ -88,71 +131,105 @@ GenericArray& GenericArray::shuffle() { } template -const T& choice(const GenericArray& array) { - return array[rnd.next(array.size())]; +GenericArray GenericArray::shuffled() const { + auto res = *this; + res.shuffle(); + return res; } -template -const GenericArray choice( - const GenericArray& array, - size_t count, - Traits... traits) -{ - TraitMap map = collectTraits(traits...); - GenericArray result(count); - - if (map.count("allowRepeats") && (int)map.at("allowRepeats")) { - for (size_t i = 0; i < count; ++i) { - result[i] = choice(array); - } - } else { - ensure(count <= array.size()); - std::vector indices = rnd.combination(array.size(), count); - for (size_t i = 0; i < count; ++i) { - result[i] = array[indices[i]]; - } - } +template +GenericArray& GenericArray::reverse() { + std::reverse(begin(), end()); + return *this; +} - return result; +template +GenericArray GenericArray::reversed() const { + auto res = *this; + res.reverse(); + return res; +} + +template +GenericArray& GenericArray::sort() { + std::sort(begin(), end()); + return *this; } template -using ArrayRepresentation = std::pair, TraitMap>; +GenericArray GenericArray::sorted() const { + auto res = *this; + res.sort(); + return res; +} -template -ArrayRepresentation repr(const GenericArray& array, Traits... traits) { - return { array, collectTraits(traits...) }; +template +GenericArray& GenericArray::add(T value) { + for (T& x: *this) { + x += value; + } + return *this; } template -std::ostream& operator<<(std::ostream& out, const ArrayRepresentation& repr) { - const GenericArray& array = repr.first; - const TraitMap& map = repr.second; +GenericArray GenericArray::added(T value) const { + auto res = *this; + res.add(value); + return res; +} - if (!map.count("printSize") || (int)map.at("printSize")) { - out << array.size() << "\n"; +template +template +GenericArray GenericArray::subseq( + const std::vector& indices) const +{ + GenericArray result; + result.reserve(indices.size()); + for (Integer idx: indices) { + result.push_back(at(idx)); } + return result; +} - int addition = map.count("addOne") && (int)map.at("addOne") ? 1 : 0; - const std::string sep = map.count("sep") ? (std::string)map.at("sep") : " "; - - bool first = true; - for (const T& x: array) { - if (!first) { - out << sep; - } else { - first = false; - } - out << x + addition; +// TODO(ifsmirnov): ever need to make it faster? +template +template +GenericArray GenericArray::subseq( + const std::initializer_list& indices) const +{ + return subseq(std::vector(indices)); +} + +template +const T& GenericArray::choice() const { + return at(rnd.next(size())); +} + +template +GenericArray GenericArray::choice(size_t count) const { + ensure(count <= size()); + + size_t n = size(); + + std::unordered_map used; + std::vector res; + for (size_t i = 0; i < count; ++i) { + size_t oldValue = used.count(n-i-1) ? used[n-i-1] : n-i-1; + size_t index = rnd.next(static_cast(n-i)); + res.push_back(used.count(index) ? used[index] : index); + used[index] = oldValue; } - return out; + + return subseq(res); } +// not sure if it would be needed ever +/* template std::ostream& operator<<(std::ostream& out, const GenericArray& array) { return out << repr(array); } - +*/ typedef GenericArray Array; typedef GenericArray Array64; @@ -164,7 +241,12 @@ using impl::Array; using impl::Array64; using impl::Arrayf; -DECLARE_NAMED_PARAMETER(printSize); -DECLARE_NAMED_PARAMETER(sep); -DECLARE_NAMED_PARAMETER(addOne); -DECLARE_NAMED_PARAMETER(allowRepeats); +template +impl::GenericArray makeArray(const std::vector& values) { + return impl::GenericArray(values); +} + +template +impl::GenericArray makeArray(const std::initializer_list& values) { + return impl::GenericArray(values); +} diff --git a/main.cpp b/main.cpp index 3af14f1..28d603d 100644 --- a/main.cpp +++ b/main.cpp @@ -1,24 +1,14 @@ +#define GLIBCXX_DEBUG #include -#include "named_arguments.h" -#include "random.h" #include "array.h" -#include "perm.h" + +#define forn(i, n) for (int i = 0; i < n; ++i) using namespace std; int main() { - impl::randomEngine.seed(1235); - - auto a = Array::random({5, 10}, 10, 50); - cout << a << endl; - - Perm p(a.size()); - p.apply(a); - cout << a << endl; - - a.shuffle(); - cout << a << endl; + rnd.seed(123); - cout << choice(a, 50, $allowRepeats = true) << endl; + cout << Array::id(10).shuffled().add1().printN() << endl; } diff --git a/named_arguments.h b/named_arguments.h deleted file mode 100644 index 07ba6ee..0000000 --- a/named_arguments.h +++ /dev/null @@ -1,68 +0,0 @@ -#pragma once -#include - -namespace impl { - -class Any { -public: - std::string s; - int i; - - Any(std::string s) : s(s), i(0) {} - Any(const char *s) : s(s), i(0) {} - Any(int i) : s(), i(i) {} - - Any(Any&& other) : s(other.s), i(other.i) {} - Any(const Any& other) : s(other.s), i(other.i) {} - - operator std::string() const { return s; } - operator int() const { return i; } - - template T as() const { - return (T)(*this); - } -}; - -class Trait { -public: - std::string name; - Any val; -}; - -typedef std::map TraitMap; - -struct TraitHelper { - TraitHelper(std::string name) : name(name) {} - std::string name; - Trait operator=(Any x) { return {name, std::move(x)}; } -}; - -int collectTraits(TraitMap& map, const Trait& trait) { - map.emplace(trait.name, std::move(trait.val)); - return 0; -} - -std::pair collectTrait(const Trait& trait) { - return { trait.name, trait.val }; -} - -__attribute__((noinline)) -__attribute__((error("\n" -" *** Do not use $smth vars as f($smth, ...), only as f($smth = true/0.5/\"hello\", ...)"))) -std::pair collectTrait(const TraitHelper&); - -template -__attribute__((noinline)) -__attribute__((error("\n" -" *** Named arguments must follow positional ones"))) -std::pair collectTrait(const T&); - -template -TraitMap collectTraits(Traits... traits) { - return { collectTrait(traits)... }; -} - -} // namespace impl - -#define DECLARE_NAMED_PARAMETER(name)\ - impl::TraitHelper $ ## name(#name) diff --git a/perm.h b/perm.h deleted file mode 100644 index 6dece84..0000000 --- a/perm.h +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once -#include - -#include "array.h" - -namespace impl { - -class Perm : public Array { -public: - Perm() {} - Perm(const Perm&) = default; - Perm& operator=(const Perm&) = default; - - Perm(size_t n); - - static Perm id(size_t n); - static Perm random(size_t n); - - template - Sequence apply(const Sequence& a); -}; - -Perm::Perm(size_t n) { - *this = Perm::id(n); -} - -Perm Perm::id(size_t n) { - Perm res; - res.resize(n); - std::iota(res.begin(), res.end(), 0); - return res; -} - -Perm Perm::random(size_t n) { - Perm res = Perm::id(n); - res.shuffle(); - return res; -} - -template -Sequence Perm::apply(const Sequence& a) { - ensure(size() == a.size()); - - Sequence result(a.size()); - for (size_t i = 0; i < size(); ++i) { - result[i] = a[at(i)]; - } - - return result; -} - -} // namespace impl - -using impl::Perm; diff --git a/random.h b/random.h index 9999708..2868a10 100644 --- a/random.h +++ b/random.h @@ -1,5 +1,4 @@ #pragma once -#include #include "common.h" @@ -25,6 +24,10 @@ class Random { randomEngine.seed(val); } + uint32_t next() { + return randomEngine(); + } + int next(int n) { // TODO(ifsmirnov): make random more uniform return randomEngine() % n; @@ -59,20 +62,6 @@ class Random { double next(double l, double r) { return l + next(r-l); } - - template - std::vector combination(T n, size_t k) { - ensure(k <= n); - std::unordered_map used; - std::vector res; - for (size_t i = 0; i < k; ++i) { - T oldValue = used.count(n-i-1) ? used[n-i-1] : n-i-1; - T index = next((T)(n-i)); - res.push_back(used.count(index) ? used[index] : index); - used[index] = oldValue; - } - return res; - } }; } // namespace impl diff --git a/repr.h b/repr.h new file mode 100644 index 0000000..38220cb --- /dev/null +++ b/repr.h @@ -0,0 +1,163 @@ +#pragma once + +#include + +namespace impl { + +template struct PTag : PTag {}; +template<> struct PTag<0> {}; +struct PTagMax : PTag<20> {}; + +struct OutputModifier { + int addition = 0; + bool printN = false; +}; + +template +class Repr { + friend std::ostream& operator<<(std::ostream& out, const Repr& repr) { + repr.print(out); + return out; + } + + friend T; + + // not sure if it would be needed ever + /* + friend Repr repr(const T& t) { + return Repr(t); + } + */ + +private: + Repr() : + object_(nullptr) + { } + + Repr(const Repr&) = default; + Repr(Repr&&) = default; + +public: + Repr(const T& object) : + object_(&object) + { } + + Repr& add1() { + ++mod_.addition; + return *this; + } + + Repr& printN(bool value = true) { + mod_.printN = value; + return *this; + } + +private: + void print(std::ostream& out) const { + if (object_) { + printValue(out, *object_, mod_, PTagMax{}); + } else { + printValue(out, static_cast(*this), mod_, PTagMax{}); + } + } + + const T* object_; + OutputModifier mod_; +}; + + +namespace detail { + +#define JNGEN_DEFINE_FUNCTION_CHECKER(name, expr)\ +template\ +class Has ## name ## Helper: public std::false_type {};\ +\ +template\ +class Has ## name ## Helper : public std::true_type {};\ + +#define JNGEN_HAS_FUNCTION(name)\ + detail::Has ## name ## Helper::value + +JNGEN_DEFINE_FUNCTION_CHECKER( + Ostream, + std::declval().operator<< (std::declval()) +) + +JNGEN_DEFINE_FUNCTION_CHECKER( + Plus, + std::declval() + 1 +) + +template +struct VectorDepth { + constexpr static int value = 0; +}; + +template class C> +struct VectorDepth> { + constexpr static int value = + std::is_base_of< + std::vector, + C + >::value ? VectorDepth::value + 1 : 0; +}; + +} // namespace detail + +#define JNGEN_DECLARE_PRINTER(constraint, priority)\ +template\ +auto printValue(\ + std::ostream& out, const T& t, const OutputModifier& mod, PTag)\ + -> typename std::enable_if::type + +JNGEN_DECLARE_PRINTER(!JNGEN_HAS_FUNCTION(Ostream), 0) +{ + // can't just write 'false' here because assertion always fails + static_assert(!std::is_same::value, "operator<< is undefined"); +} + +JNGEN_DECLARE_PRINTER(JNGEN_HAS_FUNCTION(Ostream), 1) +{ + (void)mod; + out << t; +} + +JNGEN_DECLARE_PRINTER( + JNGEN_HAS_FUNCTION(Ostream) && JNGEN_HAS_FUNCTION(Plus), 2) +{ + out << t + mod.addition; +} + + +JNGEN_DECLARE_PRINTER(detail::VectorDepth::value == 1, 3) +{ + if (mod.printN) { + out << t.size() << "\n"; + } + bool first = true; + for (const auto& x: t) { + if (first) { + first = false; + } else { + out << " "; + } + printValue(out, x, mod, PTagMax{}); + } +} + +JNGEN_DECLARE_PRINTER(detail::VectorDepth::value == 2, 4) +{ + if (mod.printN) { + out << t.size() << "\n"; + } + for (const auto& x: t) { + printValue(out, x, mod, PTagMax{}); + out << "\n"; + } +} + +} // namespace impl