65.9K
CodeProject 正在变化。 阅读更多。
Home

一个小型向量和哈希表实现,无 STL 依赖

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.50/5 (7投票s)

2022年3月17日

MIT
viewsIcon

6919

downloadIcon

58

即使在没有可靠 STL 实现的平台上,也能让你的数据发挥作用,使用这些简单但关键的类。

引言

我经常针对 Arduino 框架进行开发,并且没有可靠的跨平台 std::map 实现可以依赖,主要是因为 STL 对于许多这些设备来说并没有完全实现。此外,由于其通用性,STL 往往有一些隐藏的开销。它被设计用来处理所有场景,因此它以复杂性为代价来实现这一点。

为此,我创建了一些 std::vector<>std::map<> 的简单替代方案。这些接口与 STL 版本并不完全相同,但它们相似,缺少许多方法,包括没有删除单个项目的方法。

编写这个混乱的程序

使用起来很简单

#include <stdio.h>
#include <htcw_data.hpp>
using namespace data;
int hash(const int& x) {
    return x;
}
int main(int argc, char** argv) {
    simple_vector<int> v;
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    printf("v.begin()[0]=%d\r\n",v.begin()[0]);
    printf("v.begin()[1]=%d\r\n",v.begin()[1]);
    printf("v.begin()[2]=%d\r\n",v.begin()[2]);
    simple_fixed_map<int,int,2> test(hash);
    test.insert({1,3});
    test.insert({2,2});
    test.insert({3,1});
    printf("test.find(1)=%d\r\n",*test.find(1));
    printf("test.find(2)=%d\r\n",*test.find(2));
    printf("test.find(3)=%d\r\n",*test.find(3));
    if(test.find(4)==nullptr) {
        printf("test.find(4)=nullptr\r\n");
    }
    return 0;
}

请记住,这些类不会为你的单个项目分配内存,因此,如果你存储的是指针(例如 C 字符串或数组),这些指针必须在类外部保持有效。

整个实现如下

#pragma once
#include <stdlib.h>
namespace data {
    // dynamic vector of scalar data
    template <typename T>
    class simple_vector final {
        void* (*m_allocator)(size_t);
        void* (*m_reallocator)(void*, size_t);
        void (*m_deallocator)(void*);
        size_t m_size;          // size in number of T values
        T* m_begin;
        size_t m_capacity;      // allocated size in T values
        bool resize(size_t new_size) {
            size_t capacity = new_size;
            if (capacity > this->m_capacity) {
                size_t newcap = capacity + (this->m_capacity >> 1u);
                void* data ;
                if(this->m_begin) {
                    data = m_reallocator(this->m_begin, newcap * sizeof(T));
                } else {
                    newcap=8;
                    const size_t newsz = newcap*sizeof(T);
                    data = m_allocator(newsz);
                }
                if (data) {
                    this->m_capacity = newcap;
                    this->m_begin = (T*)data;
                } else
                    return false; //error: not enough memory
            }
            this->m_size = new_size;
            return true;
        }

    public:
        simple_vector(void*(allocator)(size_t) = ::malloc,
                    void*(reallocator)(void*, size_t) = ::realloc,
                    void(deallocator)(void*) = ::free) : 
                        m_allocator(allocator),
                        m_reallocator(reallocator),
                        m_deallocator(deallocator) {
            m_begin = nullptr;
            m_size = 0;
            m_capacity = 0;
        }
        ~simple_vector() {
            m_size = 0;
            if (m_begin != nullptr) {
                m_deallocator(m_begin);
                m_begin = nullptr;
            }
        }
        inline size_t size() const { return m_size; }
        inline size_t capacity() const { return m_capacity; }
        inline const T* cbegin() const { return m_begin; }
        inline const T* cend() const { return m_begin + m_size; }
        inline T* begin() { return m_begin; }
        inline T* end() { return m_begin + m_size; }
        void clear() {
            if(m_begin) {
                m_size = 0;
                m_capacity = 0;
                m_deallocator(m_begin);
                m_begin = nullptr;
            }
        }
        bool push_back(const T& value) {
            if (!resize(m_size + 1)) {
                return false;
            }
            m_begin[m_size - 1] = value;
            return true;
        }
    };
    template<typename TKey, typename TValue> 
    struct simple_pair {
        TKey key;
        TValue value;
        simple_pair(TKey key,TValue value) : key(key), value(value) {

        }
        simple_pair(const simple_pair& rhs) {
            key = rhs.key;
            value = rhs.value;
        }
        simple_pair& operator=(const simple_pair& rhs) {
            key = rhs.key;
            value = rhs.value;
            return *this;
        }
        simple_pair(simple_pair&& rhs) {
            key = rhs.key;
            value = rhs.value;
        }
        simple_pair& operator=(simple_pair&& rhs) {
            key = rhs.key;
            value = rhs.value;
            return *this;
        }
    };
    template<typename TKey,typename TValue, size_t Size> 
    class simple_fixed_map final {
        static_assert(Size>0,"Size must be a positive integer");
        using bucket_type = simple_vector<simple_pair<TKey,TValue>>;
        bucket_type m_buckets[Size];
        int(*m_hash_function)(const TKey&);
        size_t m_size;
    public:
        simple_fixed_map(int(hash_function)(const TKey&),
                        void*(allocator)(size_t) = ::malloc,
                        void*(reallocator)(void*, size_t) = ::realloc,
                        void(deallocator)(void*) = ::free) : 
                            m_hash_function(hash_function),
                            m_size(0) {
            for(int i = 0;i<Size;++i) {
                m_buckets[i]=bucket_type(allocator,reallocator,deallocator);
            }
        }
        using key_type = TKey;
        using mapped_type = TValue;
        using value_type = simple_pair<const TKey,TValue>;
        inline size_t size() const { return m_size; }
        void clear() {
            m_size = 0;
            for(int i = 0;i<Size;++i) {
                m_buckets->clear();
            }
        }
        bool insert(const value_type& value) {
            int h = m_hash_function(value.key)%Size;
            bucket_type& bucket = m_buckets[h];
            if(bucket.size()) {
                auto it = bucket.cbegin();
                while(it!=bucket.cend()) {
                    if(it->key==value.key) {
                        return false;
                    }
                    ++it;
                }
            }
            
            if(bucket.push_back({value.key,value.value})) {
                ++m_size;
                return true;
            }
            return false;
        }
        const mapped_type* find(const key_type& key) const {
            int h = m_hash_function(key)%Size;
            const bucket_type& bucket = m_buckets[h];
            if(bucket.size()) {
                auto it = bucket.cbegin();
                while(it!=bucket.cend()) {
                    if(it->key==key) {
                        return &it->value;
                    }
                    ++it;
                }
            }
            return nullptr;
        }
        
    };
    
}  // namespace data

包括使用 Platform IO

此库作为 Platform IO 库提供,可以通过将以下行添加到你的 platformio.ini 来安装

lib_deps = 
    codewitch-honey-crisis/htcw_data@^1.0.2 

历史

  • 2022年3月17日 - 初始提交
© . All rights reserved.