diff --git a/README.md b/README.md index 25791bd..dca614e 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,98 @@ # Tween + Tween library for Arduino + + +## Usage + +```C++ +#include + +Tween::Timeline timeline; +float target = 0.f; + +void setup() +{ + timeline.add(target, 10, 5000) // target tweens to 10 in 5000[ms] + .then(5, 5000) // then to 5 in 5000[ms] + .wait(1000) // then stops 1000[ms] + .then(0, 5000); // then to 0 in 5000[ms] + + timeline.start(); +} + +void loop() +{ + timline.update(); // must be called to tween target + + Serial.println(target); // target value tweens automatically +} +``` + +### Use Easing Function in Tween + +```C++ +timeline.add(f, 10, 5000) + .then(5, 5000) + .wait(1000) + .then(0, 5000); +``` + + +## Easing Types + +If you haven't specify the easing type, default value is `Ease::Linear`. + +- BackIn, BackOut, BackInOut +- BounceIn, BounceOut, BounceInOut +- CircIn, CircOut, CircInOut +- CubicIn, CubicOut, CubicInOut +- ElasticIn, ElasticOut, ElasticInOut +- ExpoIn, ExpoOut, ExpoInOut +- LinearIn, LinearOut, LinearInOut +- QuadIn, QuadOut, QuadInOut +- QuartIn, QuartOut, QuartInOut +- QuintIn, QuintOut, QuintInOut +- SineIn, SineOut, SineInOut + +```C++ +// alias +using Back = BackInOut; +using Bounce = BounceInOut; +using Circ = CircInOut; +using Cubic = CubicInOut; +using Elastic = ElasticInOut; +using Expo = ExpoInOut; +using Linear = LinearInOut; +using Quad = QuadInOut; +using Quart = QuartInOut; +using Quint = QuintInOut; +using Sine = SineInOut; +``` + + +## Custom Class Adaptation + +You can use custom classes if you have implemented following operators. + +- `operator+(const T&)` +- `operator-(const T&)` +- `operator*(const double)` + +If you have these operator overloads, you can use that variable completely as same as other built-in variables. +Please see `custom_class` example for details. + + +## Embedded Libraries + +- [Easing v0.1.0](https://github.com/hideakitai/Easing) +- [PollingTimer v0.2.0](https://github.com/hideakitai/PollingTimer) +- [ArxTypeTraits v0.1.11](https://github.com/hideakitai/ArxTypeTraits) +- [ArxContainer v0.3.6](https://github.com/hideakitai/ArxContainer) +- [ArxSmartPtr v0.1.1](https://github.com/hideakitai/ArxSmartPtr) +- [TeensyDirtySTLErrorSolution v0.1.0](https://github.com/hideakitai/TeensyDirtySTLErrorSolution) + + +## License + +MIT diff --git a/Tween.h b/Tween.h new file mode 100644 index 0000000..91af933 --- /dev/null +++ b/Tween.h @@ -0,0 +1,8 @@ +#ifndef ARDUINOTWEEN_H +#define ARDUINOTWEEN_H + +#include "Tween/Timeline.h" + +namespace Tween = ht::tween; + +#endif // ARDUINOTWEEN_H diff --git a/Tween/Sequence.h b/Tween/Sequence.h new file mode 100644 index 0000000..f01957d --- /dev/null +++ b/Tween/Sequence.h @@ -0,0 +1,107 @@ +#pragma once +#ifndef HT_TWEEN_SEQUENCE_H +#define HT_TWEEN_SEQUENCE_H + +#include "Types.h" +#include "Transition.h" + +namespace ht { +namespace tween { + +namespace sequence { + + struct Base + { + virtual ~Base() {} + virtual void update(const uint32_t curr_ms) = 0; + }; + + + template + class Sequence : public Base + { + struct trans_t + { + int32_t begin_ms; + int32_t end_ms; + TransitionRef ref; + }; + + T& target; + T prev_target; + Vec transitions; + + public: + + virtual ~Sequence() {} + + template + Sequence(T& from, const U& to, const int32_t in, const EasingType&, + typename std::enable_if::value>::type* = nullptr + ) + : target(from) + { + transitions.emplace_back(trans_t{0, in, make_shared>(target, from, to, in)}); + prev_target = (T)to; + } + + template + auto then(const U& to, const int32_t in) + -> typename std::enable_if::value, Sequence&>::type + { + transitions.emplace_back(trans_t{duration(), duration() + in, make_shared>(target, prev_target, to, in)}); + prev_target = (T)to; + return *this; + } + + Sequence& wait(const int32_t in) + { + transitions.emplace_back(trans_t{duration(), duration() + in, make_shared>(target, prev_target, prev_target, in)}); + return *this; + } + + virtual void update(const uint32_t curr_ms) override + { + if (transitions.empty()) return; + + const size_t idx = from_time_to_index(curr_ms); + if (idx >= transitions.size()) return; + + transitions[idx].ref->update(curr_ms - transitions[idx].begin_ms); + } + + int32_t duration() const + { + int32_t duration_ms = 0; + for (const auto& t : transitions) + duration_ms += t.ref->duration(); + return duration_ms; + } + + size_t size() const { return transitions.size(); } + bool empty() const { return transitions.size() == 0; } + void clear() { transitions.clear(); } + + private: + + size_t from_time_to_index(const int32_t ms) const + { + if (ms < 0) return 0; + for (size_t i = 0; i < transitions.size(); ++i) + if (transitions[i].end_ms > ms) + return i; + return transitions.size(); + } + + }; + +} // sequence + +template +using Sequence = sequence::Sequence; +using SequenceRef = Ref; + +} // tween +} // ht + +#endif // HT_TWEEN_SEQUENCE_H diff --git a/Tween/Timeline.h b/Tween/Timeline.h new file mode 100644 index 0000000..55c1930 --- /dev/null +++ b/Tween/Timeline.h @@ -0,0 +1,44 @@ + +#ifndef TWEEN_DUINO_TIMELINE_H +#define TWEEN_DUINO_TIMELINE_H + +#include "Types.h" +#include "Sequence.h" +#include "util/PollingTimer/PollingTimer.h" + +namespace ht { +namespace tween { + +class Timeline : public PollingTimer +{ + Map seqs; + +public: + + template + auto add(T& target, const U& to, const int32_t in) + -> typename std::enable_if::value, Sequence&>::type + { + auto p = make_shared>(target, to, in, EasingType()); + seqs.insert(make_pair((void*)&target, (SequenceRef)p)); + return *p; + } + + void update() + { + if (!isRunning()) return; + for (auto& s : seqs) + s.second->update(msec()); + } + + void clear() + { + seqs.clear(); + PollingTimer::stop(); + } +}; + +} // tween +} // ht + +#endif \ No newline at end of file diff --git a/Tween/Transition.h b/Tween/Transition.h new file mode 100644 index 0000000..20f3ab6 --- /dev/null +++ b/Tween/Transition.h @@ -0,0 +1,99 @@ +#pragma once +#ifndef HT_TWEEN_TRANSITION_H +#define HT_TWEEN_TRANSITION_H + +#include "Types.h" +#include "util/Easing/Easing.h" + +struct CRGB; +struct CHSV; + +namespace ht { +namespace tween { + +namespace transition +{ + struct Base + { + virtual ~Base() {} + virtual bool update(const int32_t t) = 0; + virtual int32_t duration() const = 0; + }; + + + template + class Transition : public Base + { + T& ref; + const T from; + const T to; + const T diff; + const int32_t duration_ms; + EasingFunc ease; + + public: + + Transition(T& target, const T& from, const T& to, const int32_t in) + : ref(target) + , from(from) + , to(to) + , diff(to - from) + , duration_ms(in) + { + } + + virtual ~Transition() {} + + virtual bool update(const int32_t t) override + { + if (t < 0) + ref = from; + else if (t > duration_ms) + ref = to; + else + { + ref = lerp(t); + return true; + } + return false; + } + + virtual int32_t duration() const { return duration_ms; } + + private: + + template + auto lerp(const float t) + -> typename std::enable_if< + !std::is_same::value && !std::is_same::value, + U + >::type + { + return diff * ease.get((float)t / (float)duration_ms) + from; + } + + template + auto lerp(const float t) + -> typename std::enable_if< + std::is_same::value || std::is_same::value, + U + >::type + { + float rgb[3]; + const float rate = ease.get((float)t / (float)duration_ms); + for (size_t i = 0; i < 3; ++i) + rgb[i] = ((float)to[i] - (float)from[i]) * rate + (float)from[i]; + return U(rgb[0], rgb[1], rgb[2]); + } + }; + +} // transition + +template +using Transition = transition::Transition; +using TransitionRef = Ref; + +} // tween +} // ht + +#endif // HT_TWEEN_TRANSITION_H diff --git a/Tween/Types.h b/Tween/Types.h new file mode 100644 index 0000000..75a1aa7 --- /dev/null +++ b/Tween/Types.h @@ -0,0 +1,43 @@ +#pragma once +#ifndef HT_TWEEN_TYPES_H +#define HT_TWEEN_TYPES_H + +#if defined(ARDUINO_ARCH_AVR)\ + || defined(ARDUINO_ARCH_MEGAAVR)\ + || defined(ARDUINO_ARCH_SAMD)\ + || defined(ARDUINO_spresense_ast) + #define HT_TWEEN_STL_DISABLED +#endif + +#include +#ifdef HT_TWEEN_STL_DISABLED + #include "Tween/util/TeensyDirtySTLErrorSolution/TeensyDirtySTLErrorSolution.h" + #include "Tween/util/ArxTypeTraits/ArxTypeTraits.h" + #include "Tween/util/ArxContainer/ArxContainer.h" + #include "Tween/util/ArxSmartPtr/ArxSmartPtr.h" +#else + #include + #include + #include +#endif + +namespace ht { +namespace tween { + +#ifdef HT_TWEEN_STL_DISABLED + template using Map = arx::map; + template using Vec = arx::vector; + template using Ref = arx::shared_ptr; + using namespace arx; +#else + template using Map = std::map; + template using Vec = std::vector; + template using Ref = std::shared_ptr; + using namespace std; +#endif // HT_TWEEN_STL_DISABLED + +} // tween +} // ht + + +#endif // HT_TWEEN_TYPES_H diff --git a/Tween/util/ArxContainer/ArxContainer.h b/Tween/util/ArxContainer/ArxContainer.h new file mode 100644 index 0000000..906318e --- /dev/null +++ b/Tween/util/ArxContainer/ArxContainer.h @@ -0,0 +1,552 @@ +#pragma once + +#ifndef ARX_RINGBUFFER_H +#define ARX_RINGBUFFER_H + +#include + +#if defined(ARDUINO_ARCH_AVR)\ + || defined(ARDUINO_ARCH_MEGAAVR)\ + || defined(ARDUINO_ARCH_SAMD)\ + || defined(ARDUINO_spresense_ast) + #define ARX_CONTAINER_DISABLED +#endif + +#ifdef ARX_CONTAINER_DISABLED + +#ifndef ARX_VECTOR_DEFAULT_SIZE +#define ARX_VECTOR_DEFAULT_SIZE 16 +#endif // ARX_VECTOR_DEFAULT_SIZE + +#ifndef ARX_DEQUE_DEFAULT_SIZE +#define ARX_DEQUE_DEFAULT_SIZE 16 +#endif // ARX_DEQUE_DEFAULT_SIZE + +#ifndef ARX_MAP_DEFAULT_SIZE +#define ARX_MAP_DEFAULT_SIZE 16 +#endif // ARX_MAP_DEFAULT_SIZE + +#ifndef ARX_TYPE_TRAITS_INITIALIZER_LIST_DEFINED +#define ARX_TYPE_TRAITS_INITIALIZER_LIST_DEFINED +namespace std +{ + template + class initializer_list + { + private: + const T* array; + size_t len; + initializer_list(const T* a, size_t l) : array(a), len(l) {} + public: + initializer_list() : array(nullptr), len(0) {} + size_t size() const { return len; } + const T *begin() const { return array; } + const T *end() const { return array + len; } + }; +} +#endif // ARX_TYPE_TRAITS_INITIALIZER_LIST_DEFINED + +namespace arx { + + namespace container + { + namespace detail + { + template + T&& move(T& t){ return static_cast(t); } + } + } + + template + class RingBuffer + { + protected: + + T queue_[N]; + int head_ {0}; + int tail_ {0}; + + public: + + RingBuffer() + : queue_() + , head_ {0} + , tail_{0} + { + } + + RingBuffer(std::initializer_list lst) + : queue_() + , head_(0) + , tail_(0) + { + for (auto it = lst.begin() ; it != lst.end() ; ++it) + { + queue_[tail_] = *it; + ++tail_; + } + } + + // copy + explicit RingBuffer(const RingBuffer& r) + : queue_() + , head_(r.head_) + , tail_(r.tail_) + { + for (size_t i = 0; i < r.size(); ++i) + queue_[i] = r.queue_[i]; + } + RingBuffer& operator= (const RingBuffer& r) + { + head_ = r.head_; + tail_ = r.tail_; + for (size_t i = 0; i < r.size(); ++i) + queue_[i] = r.queue_[i]; + return *this; + } + + // move + RingBuffer(RingBuffer&& r) + { + head_ = container::detail::move(r.head_); + tail_ = container::detail::move(r.tail_); + for (size_t i = 0; i < r.size(); ++i) + queue_[i] = container::detail::move(r.queue_[i]); + } + + RingBuffer& operator= (RingBuffer&& r) + { + head_ = container::detail::move(r.head_); + tail_ = container::detail::move(r.tail_); + for (size_t i = 0; i < r.size(); ++i) + queue_[i] = container::detail::move(r.queue_[i]); + return *this; + } + + virtual ~RingBuffer() {} + + using iterator = T*; + using const_iterator = const T*; + + size_t capacity() const { return N; }; + size_t size() const { return tail_ - head_; } + inline const T* data() const { return &(get(head_)); } + T* data() { return &(get(head_)); } + bool empty() const { return tail_ == head_; } + void clear() { head_ = 0; tail_ = 0; } + + void pop() { pop_front(); } + void pop_front() + { + if (size() == 0) return; + if (size() == 1) clear(); + else head_++; + } + void pop_back() + { + if (size() == 0) return; + if (size() == 1) clear(); + else tail_--; + } + + void push(const T& data) { push_back(data); } + void push(T&& data) { push_back(data); } + void push_back(const T& data) + { + get(tail_++) = data; + if (size() > N) ++head_; + }; + void push_back(T&& data) + { + get(tail_++) = data; + if (size() > N) ++head_; + }; + void push_front(const T& data) + { + get(head_--) = data; + if (size() > N) --tail_; + }; + void push_front(T&& data) + { + get(head_--) = data; + if (size() > N) --tail_; + }; + void emplace(const T& data) { push(data); } + void emplace(T&& data) { push(data); } + void emplace_back(const T& data) { push_back(data); } + void emplace_back(T&& data) { push_back(data); } + + const T& front() const { return get(head_); }; + T& front() { return get(head_); }; + + const T& back() const { return get(tail_ - 1); } + T& back() { return get(tail_ - 1); } + + const T& operator[] (size_t index) const { return get(head_ + (int)index); } + T& operator[] (size_t index) { return get(head_ + (int)index); } + + iterator begin() { return ptr(head_); } + iterator end() { return (queue_ + tail_); } + + const_iterator begin() const { return (const_iterator)ptr(head_); } + const_iterator end() const { return (const_iterator)(queue_ + tail_); } + + iterator erase(iterator p) + { + if (p == end()) return p; + for (T* pos = p + 1; pos != end(); ++pos) + *(pos - 1) = *pos; + --tail_; + return p; + } + + void resize(size_t sz) + { + size_t s = size(); + if (sz > size()) + { + for (size_t i = 0; i < sz - s; ++i) push(T()); + } + else if (sz < size()) + { + for (size_t i = 0; i < s - sz; ++i) pop(); + } + } + + void assign(const_iterator first, const_iterator end) + { + clear(); + const char* p = first; + while (p != end) push(*p++); + } + + void shrink_to_fit() + { + // dummy + } + + void reserve(size_t n) + { + (void)n; + // dummy + } + + void insert(const_iterator pos, const_iterator first, const_iterator last) + { + if (pos != end()) + { + size_t sz = 0; + { + iterator it = (iterator)first; + for (; it != last; ++it) ++sz; + } + iterator it = end() + sz - 1; + for (int i = sz; i > 0; --i, --it) + { + *it = *(it - sz); + } + it = (iterator)pos; + for (size_t i = 0; i < sz; ++i) + { + *it = *(first + i); + } + } + else + { + iterator it = (iterator)first; + for (; it != last; ++it) + { + push_back(*it); + } + } + } + + private: + + T& get(const int i) + { + if (i >= 0) return queue_[i % N]; + else return queue_[N - abs(i % N)]; + } + + const T& get(const int i) const + { + if (i >= 0) return queue_[i % N]; + else return queue_[N - abs(i % N)]; + } + + T* ptr(const int i) + { + if (i >= 0) return (T*)(queue_ + i % N); + else return (T*)(queue_ + N - abs(i % N)); + } + + const T* ptr(const int i) const + { + if (i >= 0) return (T*)(queue_ + i % N); + else return (T*)(queue_ + N - abs(i % N)); + } + + }; + + template + bool operator== (const RingBuffer& x, const RingBuffer& y) + { + if (x.size() != y.size()) return false; + for (size_t i = 0; i < x.size(); ++i) + if (x[i] != y[i]) return false; + return true; + } + + template + bool operator!= (const RingBuffer& x, const RingBuffer& y) + { + return !(x == y); + } + + + template + struct vector : public RingBuffer + { + vector() : RingBuffer() { } + vector(std::initializer_list lst) : RingBuffer(lst) { } + + // copy + vector(const vector& r) : RingBuffer(r) { } + + vector& operator= (const vector& r) + { + RingBuffer::operator=(r); + return *this; + } + + // move + vector(vector&& r) : RingBuffer(r) { } + + vector& operator= (vector&& r) + { + RingBuffer::operator=(r); + return *this; + } + + virtual ~vector() {} + + private: + using RingBuffer::pop; + using RingBuffer::pop_front; + using RingBuffer::push; + using RingBuffer::push_front; + using RingBuffer::emplace; + }; + + + template + struct deque : public RingBuffer + { + deque() : RingBuffer() { } + deque(std::initializer_list lst) : RingBuffer(lst) { } + + // copy + deque(const deque& r) : RingBuffer(r) { } + + deque& operator= (const deque& r) + { + RingBuffer::operator=(r); + return *this; + } + + // move + deque(deque&& r) : RingBuffer(r) { } + + deque& operator= (deque&& r) + { + RingBuffer::operator=(r); + return *this; + } + + virtual ~deque() {} + + private: + using RingBuffer::capacity; + using RingBuffer::pop; + using RingBuffer::push; + using RingBuffer::emplace; + using RingBuffer::assign; + using RingBuffer::begin; + using RingBuffer::end; + }; + + + template + struct pair + { + T1 first; + T2 second; + }; + + template + pair make_pair(const T1& t1, const T2& t2) + { + return {t1, t2}; + }; + + template + bool operator== (const pair& x, const pair& y) + { + return (x.first == y.first) && (x.second == y.second); + } + + template + bool operator!= (const pair& x, const pair& y) + { + return !(x == y); + } + + + template + struct map : public RingBuffer, N> + { + using iterator = typename RingBuffer, N>::iterator; + using const_iterator = typename RingBuffer, N>::const_iterator; + + map() : RingBuffer, N>() { } + map(std::initializer_list> lst) : RingBuffer, N>(lst) { } + + // copy + map(const map& r) : RingBuffer, N>(r) { } + + map& operator= (const map& r) + { + RingBuffer, N>::operator=(r); + return *this; + } + + // move + map(map&& r) : RingBuffer(r) { } + + map& operator= (map&& r) + { + RingBuffer, N>::operator=(r); + return *this; + } + + virtual ~map() {} + + const_iterator find(const Key& key) const + { + for (size_t i = 0; i < this->size(); ++i) + { + const_iterator it = this->begin() + i; + if (key == it->first) + return it; + } + return this->end(); + } + + pair insert(const Key& key, const T& t) + { + bool b {false}; + iterator it = find(key); + if (it == this->end()) + { + this->push(make_pair(key, t)); + b = true; + it = this->end() - 1; + } + return {it, b}; + } + + pair insert(const pair& p) + { + bool b {false}; + const_iterator it = find(p.first); + if (it == this->end()) + { + this->push(p); + b = true; + it = this->end() - 1; + } + return {(iterator)it, b}; + } + + pair emplace(const Key& key, const T& t) + { + return insert(key, t); + } + + pair emplace(const pair& p) + { + return insert(p); + } + + const T& at(const Key& key) const + { + // iterator it = find(key); + // if (it != this->end()) return it->second; + // return T(); + return find(key)->second; + } + + T& at(const Key& key) + { + // iterator it = find(key); + // if (it != this->end()) return it->second; + // return T(); + return find(key)->second; + } + + iterator erase(const iterator it) + { + iterator i = (iterator)find(it->first); + if (i != this->end()) + { + return this->erase(i); + } + return this->end(); + } + + iterator erase(const size_t index) + { + if (index < this->size()) + { + iterator it = this->begin() + index; + return this->erase(it); + } + return this->end(); + } + + const T& operator[] (const Key& key) + { + const_iterator it = find(key); + if (it != this->end()) return it->second; + + insert(::arx::make_pair(key, T())); + return this->back().second; + } + + private: + + using RingBuffer, N>::capacity; + using RingBuffer, N>::data; + using RingBuffer, N>::pop; + using RingBuffer, N>::pop_front; + using RingBuffer, N>::pop_back; + using RingBuffer, N>::push; + using RingBuffer, N>::push_back; + using RingBuffer, N>::push_front; + using RingBuffer, N>::emplace_back; + using RingBuffer, N>::front; + using RingBuffer, N>::back; + using RingBuffer, N>::resize; + using RingBuffer, N>::assign; + using RingBuffer, N>::shrink_to_fit; + }; + +} // namespace arx + +template +using ArxRingBuffer = arx::RingBuffer; + + +#endif // ARX_CONTAINER_DISABLED +#endif // ARX_RINGBUFFER_H diff --git a/Tween/util/ArxContainer/LICENSE b/Tween/util/ArxContainer/LICENSE new file mode 100644 index 0000000..8c86460 --- /dev/null +++ b/Tween/util/ArxContainer/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Hideaki Tai + +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. diff --git a/Tween/util/ArxContainer/README.md b/Tween/util/ArxContainer/README.md new file mode 100644 index 0000000..478a147 --- /dev/null +++ b/Tween/util/ArxContainer/README.md @@ -0,0 +1,166 @@ +# ArxContainer + +C++ container-like classes (vector, map, etc.) for Arduino which cannot use STL + +## Note + +`ArxContainer` is C++ container-__like__ classes for Arduino. +All of the functions is not supported currently. +Detail of these containers are described in Detail section. + +## Supported Container Types + +- `vector` +- `map` (`pair`) +- `deque` + + +## Supported Boards + +This library is currently enabled only if you use following architecture. +Please use C++ Standard Template Library for other boards. + +- AVR (Uno, Nano, Mega, etc.) +- MEGAAVR (Uno WiFi, Nano Ecery, etc.) +- SAMD (Zero, MKR, M0, etc.) +- SPRESENSE + + +## Usage + +### vector + +```C++ +// initialize with initializer_list +arx::vector vs {1, 2, 3}; + +// add contents +for (size_t i = 4; i <= 5; ++i) + vs.push_back(i); + +// index access +for (size_t i = 0; i < vs.size(); ++i) + Serial.println(vs[i]); + +// range-based access +for (const auto& v : vs) + Serial.println(v); +``` + +### map + +``` C++ +// initialize with initializer_list +arx::map mp {{"one", 1}, {"two", 2}}; + +// add contents +mp.insert("three", 3); +mp["four"] = 4; + +// range based access +for (const auto& m : mp) +{ + Serial.print("{"); + Serial.print(m.first); Serial.print(","); + Serial.print(m.second); + Serial.println("}"); +} + +// key access +Serial.print("one = "); Serial.println(mp["one"]); +Serial.print("two = "); Serial.println(mp["two"]); +Serial.print("three = "); Serial.println(mp["three"]); +Serial.print("four = "); Serial.println(mp["four"]); +``` + +### deque + +```C++ +// initialize with initializer_list +arx::deque dq {1, 2, 3}; + +// add contents +for (int i = 4; i <= 5; ++i) + dq.push_back(i); + +// index access +for (int i = 0; i < dq.size(); ++i) + Serial.print(dq[i]); +``` + + +## Detail + +`ArxContainer` is C++ container-__like__ classes for Arduino. +This library is based on `arx::RingBuffer` and `arx::xxxx` is limited-size container. +`arx::RingBuffer` can be used as: + +```C++ +ArxRingBuffer buffer; + +buffer.push(1); +buffer.push(2); +buffer.push(3); + +for(size_t i = 0; i < buffer.size(); ++i) + Serial.println(buffer[i]); + +buffer.pop(); + +for(auto& b : buffer) + Serial.println(b); +``` + +`arx::xxxx` are derived from `RingBuffer` and defined as: + +``` C++ +namespace arx { + template + struct vector : public RingBuffer + + template + struct map : public RingBuffer, N> + + template + struct deque : public RingBuffer +} +``` + +So range-based loop cannot be applyed to `arx::deque` (iterator is not continuous because it is based on `RingBuffer`). + + +### Manage Size Limit of Container + +Global default size of container can be changed by defining these macros before `#include `. + +``` C++ +#define ARX_VECTOR_DEFAULT_SIZE XX // default: 16 +#define ARX_MAP_DEFAULT_SIZE XX // default: 16 +#define ARX_DEQUE_DEFAULT_SIZE XX // default: 16 +``` + +Or you can change each container size by template argument. + +``` C++ +arx::vector vs; +arx::map ms; +arx::deque ds; +``` + +## Roadmap + +This library will be updated if I want to use more container interfaces on supported boards shown above. +PRs are welcome! + + +## Used Inside of + +- [Packetizer](https://github.com/hideakitai/Packetizer) +- [MsgPack](https://github.com/hideakitai/MsgPack) +- [MsgPacketizer](https://github.com/hideakitai/MsgPacketizer) +- [ArduinoOSC](https://github.com/hideakitai/ArduinoOSC) + + +## License + +MIT diff --git a/Tween/util/ArxContainer/library.json b/Tween/util/ArxContainer/library.json new file mode 100644 index 0000000..1ddeef3 --- /dev/null +++ b/Tween/util/ArxContainer/library.json @@ -0,0 +1,20 @@ +{ + "name": "ArxContainer", + "keywords": "ringbuffer, vector, deque, map", + "description": "C++ container-like classes (vector, map, etc.) for Arduino which cannot use STL", + "repository": + { + "type": "git", + "url": "https://github.com/hideakitai/ArxContainer.git" + }, + "authors": + { + "name": "Hideaki Tai", + "url": "https://github.com/hideakitai", + "maintainer": true + }, + "version": "0.3.6", + "license": "MIT", + "frameworks": "arduino", + "platforms": "*" +} diff --git a/Tween/util/ArxContainer/library.properties b/Tween/util/ArxContainer/library.properties new file mode 100644 index 0000000..cfa6d96 --- /dev/null +++ b/Tween/util/ArxContainer/library.properties @@ -0,0 +1,9 @@ +name=ArxContainer +version=0.3.6 +author=hideakitai +maintainer=hideakitai +sentence=C++ container-like classes (vector, map, etc.) for Arduino which cannot use STL +paragraph=C++ container-like classes (vector, map, etc.) for Arduino which cannot use STL +category=Data Storage +url=https://github.com/hideakitai +architectures=* diff --git a/Tween/util/ArxSmartPtr/ArxSmartPtr.h b/Tween/util/ArxSmartPtr/ArxSmartPtr.h new file mode 100644 index 0000000..a2c163b --- /dev/null +++ b/Tween/util/ArxSmartPtr/ArxSmartPtr.h @@ -0,0 +1,19 @@ +#pragma once + +#ifndef ARX_SMART_PTR_H +#define ARX_SMART_PTR_H + +#include + +#if defined(ARDUINO_ARCH_AVR)\ + || defined(ARDUINO_ARCH_MEGAAVR)\ + || defined(ARDUINO_ARCH_SAMD)\ + || defined(ARDUINO_spresense_ast) + #define ARX_SMART_PTR_DISABLED +#endif + +#ifdef ARX_SMART_PTR_DISABLED + #include "ArxSmartPtr/shared_ptr.h" +#endif + +#endif // ARX_SMART_PTR_H diff --git a/Tween/util/ArxSmartPtr/ArxSmartPtr/LICENSE_1_0.txt b/Tween/util/ArxSmartPtr/ArxSmartPtr/LICENSE_1_0.txt new file mode 100644 index 0000000..127a5bc --- /dev/null +++ b/Tween/util/ArxSmartPtr/ArxSmartPtr/LICENSE_1_0.txt @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +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, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/Tween/util/ArxSmartPtr/ArxSmartPtr/detail/shared_count.h b/Tween/util/ArxSmartPtr/ArxSmartPtr/detail/shared_count.h new file mode 100644 index 0000000..4122cfa --- /dev/null +++ b/Tween/util/ArxSmartPtr/ArxSmartPtr/detail/shared_count.h @@ -0,0 +1,157 @@ +#pragma once + +#ifndef ARX_SMART_PTR_DETAIL_SHARED_COUNT_H +#define ARX_SMART_PTR_DETAIL_SHARED_COUNT_H + +#include + +// imported and simplified from https://github.com/boostorg/smart_ptr + +namespace arx +{ + namespace detail + { + class sp_counted_base + { + sp_counted_base(const sp_counted_base&) = delete; + sp_counted_base& operator= (const sp_counted_base&) = delete; + + int use_count_; + + public: + + sp_counted_base() : use_count_(1) {} + virtual ~sp_counted_base() {} + + virtual void dispose() = 0; + + void add_ref() + { + ++use_count_; + } + + void release() + { + if (--use_count_ == 0) + dispose(); + } + + long use_count() const + { + return static_cast(use_count_); + } + }; + + + template + class sp_counted_impl : public sp_counted_base + { + T* ptr; + + sp_counted_impl(const sp_counted_impl&) = delete; + sp_counted_impl& operator= (const sp_counted_impl&) = delete; + + typedef sp_counted_impl this_type; + + public: + + sp_counted_impl(T* ptr) : ptr(ptr) {} + virtual ~sp_counted_impl() {} + + virtual void dispose() override + { + delete ptr; + } + }; + + + + class shared_count + { + private: + + sp_counted_base* pi_; + + public: + + shared_count() : pi_(0) + { + } + + explicit shared_count(sp_counted_base* p) : pi_(p) + { + } + + template + explicit shared_count(Y* p) : pi_(0) + { + pi_ = new sp_counted_impl(p); + + if(pi_ == 0) + { + delete p; + } + } + + ~shared_count() + { + if(pi_ != 0) pi_->release(); + } + + shared_count(const shared_count& r) : pi_(r.pi_) + { + if(pi_ != 0) pi_->add_ref(); + } + + shared_count(shared_count&& r) : pi_(r.pi_) + { + r.pi_ = 0; + } + + shared_count& operator= (const shared_count& r) + { + sp_counted_base* tmp = r.pi_; + if(tmp != pi_) + { + if(tmp != 0) tmp->add_ref(); + if(pi_ != 0) pi_->release(); + pi_ = tmp; + } + return *this; + } + + void swap(shared_count& r) + { + sp_counted_base* tmp = r.pi_; + r.pi_ = pi_; + pi_ = tmp; + } + + long use_count() const + { + return (pi_ != 0) ? pi_->use_count() : 0; + } + + bool unique() const + { + return use_count() == 1; + } + + bool empty() const + { + return pi_ == 0; + } + + friend inline bool operator== (const shared_count& a, const shared_count& b) + { + return a.pi_ == b.pi_; + } + }; + + } // namespace detail + +} // namespace arx + + + +#endif // ARX_SMART_PTR_DETAIL_SHARED_COUNT_H diff --git a/Tween/util/ArxSmartPtr/ArxSmartPtr/shared_ptr.h b/Tween/util/ArxSmartPtr/ArxSmartPtr/shared_ptr.h new file mode 100644 index 0000000..25a3bea --- /dev/null +++ b/Tween/util/ArxSmartPtr/ArxSmartPtr/shared_ptr.h @@ -0,0 +1,375 @@ +#pragma once + +#ifndef ARX_SMART_PTR_SHARED_PTR_H +#define ARX_SMART_PTR_SHARED_PTR_H + +#include +#include "detail/shared_count.h" + +// imported and simplified from https://github.com/boostorg/smart_ptr + +namespace arx { + + template class shared_ptr; + + namespace sp + { + namespace detail + { + typedef decltype(nullptr) nullptr_t; + + template T&& move(T& t) { return static_cast(t); } + + template T forward(T t) { return t; } + + template + void swap(T& a, T& b) + { + T t = move(a); + a = move(b); + b = move(t); + } + } + + // element, element_type + + template struct element { typedef T type; }; + template struct element { typedef T type; }; + template struct element { typedef T type; }; + + // dereference, return type of operator* + + template struct dereference { typedef T& type; }; + template<> struct dereference { typedef void type; }; + template<> struct dereference { typedef void type; }; + template<> struct dereference { typedef void type; }; + template<> struct dereference { typedef void type; }; + template struct dereference { typedef void type; }; + template struct dereference { typedef void type; }; + + // member_access, return type of operator-> + + template struct member_access { typedef T* type; }; + template struct member_access { typedef void type; }; + template struct member_access { typedef void type; }; + + // array_access, return type of operator[] + + template struct array_access { typedef void type; }; + template struct array_access { typedef T& type; }; + template struct array_access { typedef T& type; }; + } + + + template class shared_ptr + { + public: + + typedef typename sp::element::type element_type; + + private: + + typedef shared_ptr this_type; + + template friend class shared_ptr; + + element_type* px; + detail::shared_count pn; + + public: + + shared_ptr() : px(0), pn() + { + } + + shared_ptr(sp::detail::nullptr_t) : px(0), pn() + { + } + + template + explicit shared_ptr(Y* p): px(p), pn() + { + detail::shared_count(p).swap(pn); + } + + shared_ptr(const shared_ptr& r) : px(r.px), pn(r.pn) + { + } + + template + shared_ptr(const shared_ptr& r) + : px(r.px), pn(r.pn) + { + } + + template + shared_ptr(const shared_ptr& r, element_type* p) : px(p), pn(r.pn) + { + } + + shared_ptr& operator= (const shared_ptr& r) + { + this_type(r).swap(*this); + return *this; + } + + template + shared_ptr& operator= (const shared_ptr& r) + { + this_type(r).swap(*this); + return *this; + } + + shared_ptr(shared_ptr&& r) : px(r.px), pn() + { + pn.swap(r.pn); + r.px = 0; + } + + template + shared_ptr(shared_ptr&& r) + : px(r.px), pn() + { + pn.swap( r.pn ); + r.px = 0; + } + + shared_ptr& operator= (shared_ptr&& r) + { + this_type(static_cast(r)).swap(*this); + return *this; + } + + template + shared_ptr & operator= (shared_ptr&& r) + { + this_type(static_cast&&>(r)).swap(*this); + return *this; + } + + template + shared_ptr(shared_ptr&& r, element_type* p) : px(p), pn() + { + pn.swap( r.pn ); + r.px = 0; + } + + shared_ptr& operator= (sp::detail::nullptr_t) + { + this_type().swap(*this); + return *this; + } + + void reset() + { + this_type().swap(*this); + } + + template + void reset(Y* p) + { + this_type(p).swap(*this); + } + + template + void reset(const shared_ptr& r, element_type* p) + { + this_type(r, p).swap(*this); + } + + template + void reset(shared_ptr&& r, element_type* p) + { + this_type(static_cast&&>(r), p).swap(*this); + } + + typename sp::dereference::type operator* () const + { + return *px; + } + + typename sp::member_access::type operator-> () const + { + return px; + } + + typename sp::array_access::type operator[] (size_t i) const + { + return static_cast::type>(px[i]); + } + + element_type* get() const + { + return px; + } + + explicit operator bool () const + { + return px != 0; + } + + bool operator! () const + { + return px == 0; + } + + bool unique() const + { + return pn.unique(); + } + + long use_count() const + { + return pn.use_count(); + } + + void swap(shared_ptr& other) + { + sp::detail::swap(px, other.px); + pn.swap(other.pn); + } + + }; // shared_ptr + + + + template + inline bool operator== (const shared_ptr& a, const shared_ptr& b) + { + return a.get() == b.get(); + } + + template + inline bool operator!= (const shared_ptr& a, const shared_ptr& b) + { + return a.get() != b.get(); + } + + template + inline bool operator== (const shared_ptr& p, sp::detail::nullptr_t) + { + return p.get() == 0; + } + + template + inline bool operator== (sp::detail::nullptr_t, const shared_ptr& p ) + { + return p.get() == 0; + } + + template + inline bool operator!= (const shared_ptr& p, sp::detail::nullptr_t) + { + return p.get() != 0; + } + + template + inline bool operator!= (sp::detail::nullptr_t, const shared_ptr& p ) + { + return p.get() != 0; + } + + template + inline void swap(const shared_ptr& a, const shared_ptr& b) + { + a.swap(b); + } + + template + shared_ptr static_pointer_cast(const shared_ptr& r) + { + (void)static_cast(static_cast(0)); + + typedef typename shared_ptr::element_type E; + E* p = static_cast(r.get()); + return shared_ptr(r, p); + } + + template + shared_ptr const_pointer_cast(const shared_ptr& r) + { + (void)const_cast(static_cast(0)); + + typedef typename shared_ptr::element_type E; + E* p = const_cast(r.get()); + return shared_ptr(r, p); + } + + template + shared_ptr dynamic_pointer_cast(const shared_ptr& r) + { + (void)dynamic_cast(static_cast(0)); + + typedef typename shared_ptr::element_type E; + E* p = dynamic_cast(r.get()); + return p ? shared_ptr(r, p): shared_ptr(); + } + + template + shared_ptr reinterpret_pointer_cast(const shared_ptr& r) + { + (void)reinterpret_cast(static_cast(0) ); + + typedef typename shared_ptr::element_type E; + E* p = reinterpret_cast(r.get()); + return shared_ptr(r, p); + } + + template + shared_ptr static_pointer_cast(shared_ptr&& r) + { + (void)static_cast(static_cast(0)); + + typedef typename shared_ptr::element_type E; + E* p = static_cast(r.get()); + return shared_ptr(sp::detail::move(r), p); + } + + template + shared_ptr const_pointer_cast(shared_ptr&& r) + { + (void)const_cast(static_cast(0)); + + typedef typename shared_ptr::element_type E; + E* p = const_cast(r.get()); + return shared_ptr(sp::detail::move(r), p); + } + + template + shared_ptr dynamic_pointer_cast(shared_ptr&& r) + { + (void)dynamic_cast(static_cast(0)); + + typedef typename shared_ptr::element_type E; + E* p = dynamic_cast(r.get()); + return p ? shared_ptr(sp::detail::move(r), p) : shared_ptr(); + } + + template + shared_ptr reinterpret_pointer_cast(shared_ptr&& r) + { + (void)reinterpret_cast(static_cast(0)); + + typedef typename shared_ptr::element_type E; + E* p = reinterpret_cast(r.get()); + return shared_ptr(sp::detail::move(r), p); + } + + + // make_shared : for compatibility, just an alias of constructor + + template + shared_ptr make_shared() + { + return shared_ptr(new T); + } + + template + shared_ptr make_shared(Args&&... args) + { + return shared_ptr(new T(sp::detail::forward(args)...)); + } + +} // arx + +#endif // ARX_SMART_PTR_SHARED_PTR_H diff --git a/Tween/util/ArxSmartPtr/LICENSE b/Tween/util/ArxSmartPtr/LICENSE new file mode 100644 index 0000000..6f5269b --- /dev/null +++ b/Tween/util/ArxSmartPtr/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Hideaki Tai + +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. diff --git a/Tween/util/ArxSmartPtr/README.md b/Tween/util/ArxSmartPtr/README.md new file mode 100644 index 0000000..24bd3ae --- /dev/null +++ b/Tween/util/ArxSmartPtr/README.md @@ -0,0 +1,77 @@ +# ArxSmartPtr + +C++ smart pointer-like classes for Arduino which can't use standard smart pointers + + +## Note + +`ArxSmartPtr` is C++ smart pointer-__like__ classes for Arduino. +All of the functions is not supported currently. +Almost all functions are imported and simplified based on [Boost.SmartPtr](https://github.com/boostorg/smart_ptr). + + +## Supported SmartPtr + +- `shared_ptr` + + +### Limitations + +- Custom Deleter cannot be used +- Custom Allocater cannot be used +- `make_shared` is just an alias for constructor +- namespace `arx` is used instead of `std` + + +## Supported Boards + +This library is currently enabled only if you use following architecture. +Please use C++ Standard Template Library for other boards. + +- AVR (Uno, Nano, Mega, etc.) +- MEGAAVR (Uno WiFi, Nano Ecery, etc.) +- SAMD (Zero, MKR, M0, etc.) +- SPRESENSE + + +## Usage + +Please see example for more information. + +``` C++ +{ + Serial.println("start"); + arx::shared_ptr t1(new Base(4)); + arx::shared_ptr t2; + { + arx::shared_ptr t3(new Base(5)); + arx::shared_ptr t4(new Base(6)); + t2 = t3; + } + Serial.println("end"); +} +// start +// Base::Constructor 4 +// Base::Constructor 5 +// Base::Constructor 6 +// Base::Destructor 6 +// end +// Base::Destructor 5 +// Base::Destructor 4 +``` + +## Used Inside of + +- [Packetizer](https://github.com/hideakitai/Packetizer) +- [MsgPacketizer](https://github.com/hideakitai/MsgPacketizer) +- [ArduinoOSC](https://github.com/hideakitai/ArduinoOSC) + + +## Roadmap + +This library will be updated if I want to use more smart pointer interfaces on supported boards shown above. +PRs are welcome! + +## License + +MIT diff --git a/Tween/util/ArxSmartPtr/library.json b/Tween/util/ArxSmartPtr/library.json new file mode 100644 index 0000000..461f97b --- /dev/null +++ b/Tween/util/ArxSmartPtr/library.json @@ -0,0 +1,20 @@ +{ + "name": "ArxSmartPtr", + "keywords": "smart ptr, shared ptr, stl", + "description": "C++ smart pointer-like classes for Arduino which cannot use standard smart pointers", + "repository": + { + "type": "git", + "url": "https://github.com/hideakitai/ArxSmartPtr.git" + }, + "authors": + { + "name": "Hideaki Tai", + "url": "https://github.com/hideakitai", + "maintainer": true + }, + "version": "0.1.1", + "license": "MIT", + "frameworks": "arduino", + "platforms": "*" +} diff --git a/Tween/util/ArxSmartPtr/library.properties b/Tween/util/ArxSmartPtr/library.properties new file mode 100644 index 0000000..030b4a4 --- /dev/null +++ b/Tween/util/ArxSmartPtr/library.properties @@ -0,0 +1,9 @@ +name=ArxSmartPtr +version=0.1.1 +author=hideakitai +maintainer=hideakitai +sentence=C++ smart pointer-like classes for Arduino which cannot use standard smart pointers +paragraph=C++ smart pointer-like classes for Arduino which cannot use standard smart pointers +category=Data Storage +url=https://github.com/hideakitai +architectures=* diff --git a/Tween/util/ArxTypeTraits/ArxTypeTraits.h b/Tween/util/ArxTypeTraits/ArxTypeTraits.h new file mode 100644 index 0000000..717cd52 --- /dev/null +++ b/Tween/util/ArxTypeTraits/ArxTypeTraits.h @@ -0,0 +1,27 @@ +#pragma once + +#ifndef ARX_TYPE_TRAITS_H +#define ARX_TYPE_TRAITS_H + +#if defined(ARDUINO_ARCH_AVR)\ + || defined(ARDUINO_ARCH_MEGAAVR)\ + || defined(ARDUINO_ARCH_SAMD)\ + || defined(ARDUINO_spresense_ast) + #define ARX_TYPE_TRAITS_DISABLED + #if defined(ARDUINO_ARCH_MEGAAVR)\ + || defined(ARDUINO_ARCH_SAMD)\ + || defined(ARDUINO_spresense_ast) + #define ARX_TYPE_TRAITS_NEW_DISABLED + #endif +#endif + +#include +#ifndef ARX_TYPE_TRAITS_DISABLED + #include + #include + #include +#endif + +#include "ArxTypeTraits/type_traits.h" + +#endif // ARX_TYPE_TRAITS_H diff --git a/Tween/util/ArxTypeTraits/ArxTypeTraits/functional.h b/Tween/util/ArxTypeTraits/ArxTypeTraits/functional.h new file mode 100644 index 0000000..ed1ff17 --- /dev/null +++ b/Tween/util/ArxTypeTraits/ArxTypeTraits/functional.h @@ -0,0 +1,149 @@ +#pragma once + +#ifndef ARX_TYPE_TRAITS_FUNCTIONAL_H +#define ARX_TYPE_TRAITS_FUNCTIONAL_H + +#include + +#ifdef ARX_TYPE_TRAITS_NEW_DISABLED + void* operator new (const size_t size, void* ptr) { (void)size; return ptr; } +#else + #include +#endif + +#ifdef ARX_TYPE_TRAITS_DISABLED + +namespace std { + + // reference: + // stack overflow https://stackoverflow.com/questions/32074410/stdfunction-bind-like-type-erasure-without-standard-c-library + + template + struct function; + + template + class function + { + struct vtable_t + { + void (*mover)(void* src, void* dest); + void (*destroyer)(void*); + R (*invoke)(void const* t, Args&&... args); + + template + static vtable_t const* get() + { + static const vtable_t table = + { + // mover + [] (void* src, void* dest) + { + new(dest) T(move(*static_cast(src))); + }, + // destroyer + [] (void* t) + { + static_cast(t)->~T(); + }, + // invoke + [] (void const* t, Args&&... args) -> R + { + return (*static_cast(t))(std::forward(args)...); + } + }; + return &table; + } + }; + + vtable_t const* table {nullptr}; + void* data {nullptr}; + + public: + + template < + class Func, + class dF = typename std::decay::type, + typename enable_if {}>::type* = nullptr, + typename enable_if ::type, R>{}>::type* = nullptr + > + function(const Func& f) + : table(vtable_t::template get()) + { + data = reinterpret_cast(new Func(f)); + } + function(const function& o) + : table(o.table) + { + data = o.data; + } + function(function&& o) + : table(o.table) + { + if (table) table->mover(o.data, data); + } + function() + { + } + ~function() + { + if (table) table->destroyer(data); + } + + function& operator= (const function& o) + { + this->~function(); + new(this) function(move(o)); + return *this; + } + function& operator= (function&& o) + { + this->~function(); + new(this) function(move(o)); + return *this; + } + function& operator= (std::nullptr_t p) + { + (void)p; + this->~function(); + return *this; + } + + explicit operator bool() const + { + return table; + } + + R operator()(Args...args) const + { + return table->invoke(data, forward(args)...); + } + }; + + template + inline bool operator== (const function& f, std::nullptr_t) + { + return !static_cast(f); + } + + template + inline bool operator== (std::nullptr_t, const function& f) + { + return !static_cast(f); + } + + template + inline bool operator!= (const function& f, std::nullptr_t) + { + return static_cast(f); + } + + template + inline bool operator!= (std::nullptr_t, const function& f) + { + return static_cast(f); + } + +} // namespace std + +#endif // ARX_TYPE_TRAITS_DISABLED +#endif // ARX_TYPE_TRAITS_FUNCTIONAL_H diff --git a/Tween/util/ArxTypeTraits/ArxTypeTraits/tuple.h b/Tween/util/ArxTypeTraits/ArxTypeTraits/tuple.h new file mode 100644 index 0000000..f8d765b --- /dev/null +++ b/Tween/util/ArxTypeTraits/ArxTypeTraits/tuple.h @@ -0,0 +1,77 @@ +#pragma once + +#ifndef ARX_TYPE_TRAITS_TUPLE_H +#define ARX_TYPE_TRAITS_TUPLE_H + +#ifdef ARX_TYPE_TRAITS_DISABLED + +namespace std { + + // https://theolizer.com/cpp-school2/cpp-school2-15/ + // https://wandbox.org/permlink/C0BWIzjqg4iO3kKZ + + template + struct tuple + { + tuple() {} + }; + + template + class tuple : public tuple + { + template friend struct get_helper; + tFirst mMember; + public: + tuple(tFirst const& iFirst, tRest const&... iRest) + : tuple(iRest...) + , mMember(iFirst) + { } + constexpr tuple() {} + }; + + template + struct get_helper { }; + template + struct get_helper<0, tFirst, tRest...> + { + typedef tFirst type; + static type& get(tuple& iTuple) + { + return iTuple.mMember; + } + }; + template + struct get_helper + { + typedef typename get_helper::type type; + static type& get(tuple& iTuple) + { + return get_helper::get(iTuple); + } + }; + + template + typename get_helper::type& get(tuple& iTuple) + { + return get_helper::get(iTuple); + } + + template class tuple_size; + template class tuple_size; + template class tuple_size; + template class tuple_size; + template + class tuple_size > + : public integral_constant {}; + + template + auto make_tuple(Types&&... args) + -> std::tuple::type...> + { + return std::tuple::type...>(std::forward::type>(args)...); + } + +} // namespace std + +#endif // ARX_TYPE_TRAITS_DISABLED +#endif // ARX_TYPE_TRAITS_TUPLE_H diff --git a/Tween/util/ArxTypeTraits/ArxTypeTraits/type_traits.h b/Tween/util/ArxTypeTraits/ArxTypeTraits/type_traits.h new file mode 100644 index 0000000..05784e3 --- /dev/null +++ b/Tween/util/ArxTypeTraits/ArxTypeTraits/type_traits.h @@ -0,0 +1,626 @@ +#pragma once + +#ifndef ARX_TYPE_TRAITS_TYPE_TRAITS_H +#define ARX_TYPE_TRAITS_TYPE_TRAITS_H + +#ifdef ARX_TYPE_TRAITS_DISABLED + +#ifdef max + #undef max + template + constexpr auto max(T1 x, T2 y) + -> decltype(x + y) + { + return (x > y) ? x : y; + } +#endif +#ifdef min + #undef min + template + constexpr auto min(T1 x, T2 y) + -> decltype(x + y) + { + return (x < y) ? x : y; + } +#endif + +#include +#include +#include + +namespace std { + + using nullptr_t = decltype(nullptr); + + // numeric_limits + + template + struct numeric_limits + { + static constexpr T max() { return T(); } + static constexpr T min() { return T(); } + }; + template <> constexpr bool numeric_limits::max() { return true; } + template <> constexpr char numeric_limits::max() { return CHAR_MAX; } + template <> constexpr signed char numeric_limits::max() { return SCHAR_MAX; } + template <> constexpr unsigned char numeric_limits::max() { return UCHAR_MAX; } + template <> constexpr wchar_t numeric_limits::max() { return WCHAR_MAX; } + // template <> constexpr char8_t numeric_limits::max() { return UCHAR_MAX; } + template <> constexpr char16_t numeric_limits::max() { return UINT_LEAST16_MAX; } + template <> constexpr char32_t numeric_limits::max() { return UINT_LEAST32_MAX; } + template <> constexpr short numeric_limits::max() { return SHRT_MAX; } + template <> constexpr unsigned short numeric_limits::max() { return USHRT_MAX; } + template <> constexpr int numeric_limits::max() { return INT_MAX; } + template <> constexpr unsigned int numeric_limits::max() { return UINT_MAX; } + template <> constexpr long numeric_limits::max() { return LONG_MAX; } + template <> constexpr unsigned long numeric_limits::max() { return ULONG_MAX; } + // template <> constexpr long long numeric_limits::max() { return LLONG_MAX; } + // template <> constexpr unsigned long long numeric_limits::max() { return ULLONG_MAX; } + template <> constexpr float numeric_limits::max() { return FLT_MAX; } + template <> constexpr double numeric_limits::max() { return DBL_MAX; } + template <> constexpr long double numeric_limits::max() { return LDBL_MAX; } + + template <> constexpr bool numeric_limits::min() { return false; } + template <> constexpr char numeric_limits::min() { return CHAR_MIN; } + template <> constexpr signed char numeric_limits::min() { return SCHAR_MIN; } + template <> constexpr unsigned char numeric_limits::min() { return 0; } + template <> constexpr wchar_t numeric_limits::min() { return WCHAR_MIN; } + // template <> constexpr char8_t numeric_limits::min() { return 0; } + template <> constexpr char16_t numeric_limits::min() { return 0; } + template <> constexpr char32_t numeric_limits::min() { return 0; } + template <> constexpr short numeric_limits::min() { return SHRT_MIN; } + template <> constexpr unsigned short numeric_limits::min() { return 0; } + template <> constexpr int numeric_limits::min() { return INT_MIN; } + template <> constexpr unsigned int numeric_limits::min() { return 0; } + template <> constexpr long numeric_limits::min() { return LONG_MIN; } + template <> constexpr unsigned long numeric_limits::min() { return 0; } + // template <> constexpr long long numeric_limits::min() { return LLONG_MIN; } + // template <> constexpr unsigned long long numeric_limits::min() { return 0; } + template <> constexpr float numeric_limits::min() { return FLT_MIN; } + template <> constexpr double numeric_limits::min() { return DBL_MIN; } + template <> constexpr long double numeric_limits::min() { return LDBL_MIN; } + + + // integral_constant + + template + struct integral_constant + { + static constexpr T value = v; + using value_type = T; + using type = integral_constant; + constexpr operator value_type() const noexcept { return value; } + constexpr value_type operator()() const noexcept { return value; } + }; + + using true_type = integral_constant; + using false_type = integral_constant; + + + template + T declval(); // no implementation + + + template + struct enable_if; + template + struct enable_if { using type = T; }; + + + template + struct conditional { using type = T; }; + template + struct conditional { using type = F; }; + + + template struct remove_cv { using type = T; }; + template struct remove_cv { using type = T; }; + template struct remove_cv { using type = T; }; + template struct remove_cv { using type = T; }; + + template struct remove_const { using type = T; }; + template struct remove_const { using type = T; }; + + template struct remove_volatile { using type = T; }; + template struct remove_volatile { using type = T; }; + + template struct remove_pointer { using type = T; }; + template struct remove_pointer { using type = T; }; + template struct remove_pointer { using type = T; }; + template struct remove_pointer { using type = T; }; + template struct remove_pointer { using type = T; }; + + template struct remove_reference { using type = T; }; + template struct remove_reference { using type = T; }; + template struct remove_reference { using type = T; }; + + template struct remove_extent { typedef T type; }; + template struct remove_extent { typedef T type; }; + template struct remove_extent { typedef T type; }; + + + template + T&& move(T& t){ return static_cast(t); } + template + T&& move(T&& t){ return static_cast(t); } + + + template + constexpr T&& forward(typename remove_reference::type& t) noexcept + { + return static_cast(t); + } + template + constexpr T&& forward(typename remove_reference::type&& t) noexcept + { + return static_cast(t); + } + + + namespace detail + { + template + struct type_identity { using type = T; }; + template + auto try_add_pointer(int) -> type_identity::type*>; + template + auto try_add_pointer(...) -> type_identity; + } + template + struct add_pointer : decltype(detail::try_add_pointer(0)) {}; + + + template + struct is_same : false_type {}; + template + struct is_same : true_type {}; + + + template + struct is_integral : false_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + + + template + struct is_floating_point : false_type {}; + template <> struct is_floating_point : true_type {}; + template <> struct is_floating_point : true_type {}; + template <> struct is_floating_point : true_type {}; + + + template + struct is_arithmetic + : conditional< + is_integral::value || is_floating_point::value, + true_type, + false_type + >::type + {}; + + + namespace detail + { + template ::value> + struct is_signed : integral_constant {}; + template + struct is_signed : false_type {}; + } + template + struct is_signed : detail::is_signed::type {}; + + + namespace detail + { + template::value> + struct is_unsigned : integral_constant {}; + template + struct is_unsigned : false_type {}; + } + template + struct is_unsigned : detail::is_unsigned::type {}; + + + template struct is_pointer_helper : false_type {}; + template struct is_pointer_helper : true_type {}; + template struct is_pointer : is_pointer_helper::type> {}; + + + template + struct is_array : false_type {}; + template + struct is_array : true_type {}; + template + struct is_array : true_type {}; + + + namespace details + { + template + struct Tester { using type = void; }; + template + using void_t = typename Tester::type; + templateclass Z, class, class...Ts> + struct can_apply : false_type{}; + templateclass Z, class...Ts> + struct can_apply>, Ts...> : true_type{}; + + template + using try_convert = decltype(To{declval()} ); + } + templateclass Z, class...Ts> + using can_apply = details::can_apply; + template + struct is_convertible : can_apply {}; + template<> + struct is_convertible : true_type{}; + + + // primary template + template + struct is_function : false_type { }; + // specialization for regular functions + template + struct is_function : true_type {}; + // specialization for variadic functions such as std::printf + template + struct is_function : true_type {}; + // specialization for function types that have cv-qualifiers + template + struct is_function : true_type {}; + template + struct is_function : true_type {}; + template + struct is_function : true_type {}; + template + struct is_function : true_type {}; + template + struct is_function : true_type {}; + template + struct is_function : true_type {}; + // specialization for function types that have ref-qualifiers + template + struct is_function : true_type {}; + template + struct is_function : true_type {}; + template + struct is_function : true_type {}; + template + struct is_function : true_type {}; + template + struct is_function : true_type {}; + template + struct is_function : true_type {}; + template + struct is_function : true_type {}; + template + struct is_function : true_type {}; + template + struct is_function : true_type {}; + template + struct is_function : true_type {}; + template + struct is_function : true_type {}; + template + struct is_function : true_type {}; + template + struct is_function : true_type {}; + template + struct is_function : true_type {}; + template + struct is_function : true_type {}; + template + struct is_function : true_type {}; + + + template + struct is_empty : public integral_constant { }; + + + template + class decay + { + typedef typename remove_reference::type U; + public: + typedef typename conditional< + is_array::value, + typename remove_extent::type*, + typename conditional< + is_function::value, + typename add_pointer::type, + typename remove_cv::type + >::type + >::type type; + }; + + + namespace details + { + template struct tag { using type=T; }; + template using type_t = typename Tag::type; + + template + using invoke_t = decltype( declval()(declval()...) ); + + template + struct result_of {}; + template + struct result_of>> + : tag > + {}; + } + template + using result_of = details::result_of; + + + template + void swap(T& a, T& b) + { + T t = move(a); + a = move(b); + b = move(t); + } + + +#ifndef ARX_TYPE_TRAITS_INITIALIZER_LIST_DEFINED +#define ARX_TYPE_TRAITS_INITIALIZER_LIST_DEFINED + + template + class initializer_list + { + private: + const T* array; + size_t len; + initializer_list(const T* a, size_t l) : array(a), len(l) {} + public: + initializer_list() : array(nullptr), len(0) {} + size_t size() const { return len; } + const T *begin() const { return array; } + const T *end() const { return array + len; } + }; + +#endif // ARX_TYPE_TRAITS_INITIALIZER_LIST_DEFINED + +} // namespace std + +#include "tuple.h" +#include "functional.h" + +#endif // ARX_TYPE_TRAITS_DISABLE_STL + + +#if __cplusplus < 201402L // C++11 +#if !defined(OF_VERSION_MAJOR) || !defined(TARGET_WIN32) + +namespace std { + + template + using enable_if_t = typename std::enable_if::type; + + template + using decay_t = typename std::decay::type; + + template + using remove_cv_t = typename std::remove_cv::type; + template + using remove_const_t = typename std::remove_const::type; + template + using remove_volatile_t = typename std::remove_volatile::type; + template + using remove_reference_t = typename std::remove_reference::type; + template + using remove_pointer_t = typename std::remove_pointer::type; + + template + struct integer_sequence + { + using type = integer_sequence; + using value_type = T; + static constexpr size_t size() noexcept { return sizeof...(Ts); } + }; + template + using index_sequence = integer_sequence; + + // https://stackoverflow.com/questions/17424477/implementation-c14-make-integer-sequence + + template + struct concat_impl; + template + using concat = typename concat_impl::type; + + template + struct concat_impl , index_sequence> + : index_sequence {}; + template + struct make_index_sequence_impl; + template + using make_index_sequence = typename make_index_sequence_impl::type; + template + struct make_index_sequence_impl + : concat, make_index_sequence > {}; + template<> + struct make_index_sequence_impl <0> : index_sequence<>{}; + template<> + struct make_index_sequence_impl <1> : index_sequence<0>{}; + + template + using index_sequence_for = make_index_sequence; + +} // namespace std + +#endif // !defined(OF_VERSION_MAJOR) || !defined(TARGET_WIN32) +#endif // C++11 + + +#if __cplusplus < 201703L // C++14 + +namespace std { + +#if !defined(OF_VERSION_MAJOR) || !defined(TARGET_WIN32) + + template + struct Tester { using type = void; }; + template + using void_t = typename Tester::type; + + template + struct disjunction : std::false_type {}; + template + struct disjunction : Arg::type {}; + template + struct disjunction : std::conditional>::type {}; + + template + struct conjunction : std::true_type {}; + template + struct conjunction : Arg::type {}; + template + struct conjunction : std::conditional, Arg>::type {}; + + template + struct negation : std::integral_constant {}; + +#endif // !defined(OF_VERSION_MAJOR) || !defined(TARGET_WIN32) + + // https://qiita.com/_EnumHack/items/92e6e135174f1f781dbb + // without decltype(auto) + + template + constexpr auto apply_impl(F&& f, Tuple&& t, index_sequence) + -> decltype(f(std::get(std::forward(t))...)) + { + return f(std::get(std::forward(t))...); + } + template + constexpr auto apply(F&& f, Tuple&& t) + -> decltype(apply_impl( + std::forward(f), + std::forward(t), + make_index_sequence>::value>{} + )) + { + return apply_impl( + std::forward(f), + std::forward(t), + make_index_sequence>::value>() + ); + } + +} // namespace std + +#endif // C++14 + + +// C++17, C++2a +namespace std { + + template + struct remove_cvref + { + typedef std::remove_cv_t> type; + }; + + template< class T > + using remove_cvref_t = typename remove_cvref::type; + +} // namespace std +// C++17, C++2a + + +namespace arx { // others + + template class Check, class... T> + struct is_detected_impl : std::false_type {}; + template