STL原始碼剖析之stl_deque的實現(二)
STL中deque(雙端佇列)是一種非常重要的結構,stack,與queue底層都是藉助deque.
deque(雙端佇列)是一種雙向開口的連續性空間,雙向開口意思是可以在頭尾兩端做元素的插入和刪除操作。deque和vector最大的差異在於deque允許常數時間內對起頭端進行元素的插入或移除操作,二者在於deque沒所謂的容量(capacity)觀念,因為它是動態地以分段連續空間組合而成,隨時可以增加一段新的空間並連結起來。deque採用一塊所謂的map作為主控,這裡所謂的map是一小塊連續的空間,其中每個元素都是指標,指向另一段較大的連續線性空間,稱為緩衝區。緩衝區才是deque的儲存空間主體。SGI STL允許我們指定緩衝區大小,預設值為0表示將使用512 bytes緩衝區。但是在deque在排序的時候需要借住vector,為了最高效率要將deque先完整複製到一個vector身上,將vector排序後再複製回deque.預設map_size開始大小為8個.
下面的程式碼從stl_deque中摘取,deque僅僅實現了構造物件,與插入數值。
deque無型別檔案,引用所需要的檔案
#ifndef _DEQUE_
#define _DEQUE_
#include"stl_construct.h"
#include"stl_iterator.h"
#include"type_traits.h"
#include"stl_uninitialized.h"
#include"stl_alloc.h"
#include"stl_deque.h"
#endif
stl_construct.h 構造的實現
#ifndef _STL_CONSTRUCT_H #define _STL_CONSTRUCT_H #include"type_traits.h" #include<new.h> template <class T> inline void destroy(T* pointer) { pointer->~T(); } template <class T1, class T2> inline void construct(T1* p, const T2& value) { new (p) T1(value); } template <class ForwardIterator> inline void __destroy_aux(ForwardIterator first, ForwardIterator last, __false_type) { for ( ; first < last; ++first) destroy(&*first); } template <class ForwardIterator> inline void __destroy_aux(ForwardIterator, ForwardIterator, __true_type) {} template <class ForwardIterator, class T> inline void __destroy(ForwardIterator first, ForwardIterator last, T*) { typedef typename __type_traits<T>::has_trivial_destructor trivial_destructor; __destroy_aux(first, last, trivial_destructor()); } template <class ForwardIterator> inline void destroy(ForwardIterator first, ForwardIterator last) { __destroy(first, last, value_type(first)); } #endif
stl_iterator.h 迭代器
#ifndef _STL_ITERATOR_H #define _STL_ITERATOR_H template <class T> inline T* value_type(const T*) { return (T*)(0); } template <class T> inline size_t* distance_type(const T*) { return (size_t*)(0); } struct input_iterator_tag {}; struct output_iterator_tag {}; struct forward_iterator_tag : public input_iterator_tag {}; struct bidirectional_iterator_tag : public forward_iterator_tag {}; struct random_access_iterator_tag : public bidirectional_iterator_tag {}; template <class T> inline random_access_iterator_tag iterator_category(const T*) { return random_access_iterator_tag(); } #endif
type_traits.h 萃取機制
#ifndef _TYPE_TRAITS_H
#define _TYPE_TRAITS_H
struct __true_type
{};
struct __false_type
{};
template <class type>
struct __type_traits
{
typedef __true_type this_dummy_member_must_be_first;
typedef __false_type has_trivial_default_constructor;
typedef __false_type has_trivial_copy_constructor;
typedef __false_type has_trivial_assignment_operator;
typedef __false_type has_trivial_destructor;
typedef __false_type is_POD_type;
};
struct __type_traits<int>
{
typedef __true_type this_dummy_member_must_be_first;
typedef __true_type has_trivial_default_constructor;
typedef __true_type has_trivial_copy_constructor;
typedef __true_type has_trivial_assignment_operator;
typedef __true_type has_trivial_destructor;
typedef __true_type is_POD_type;
};
#endif
stl_uninitialized.h 未初始化的引數
#ifndef _STL_UNINITIALIZED_H
#define _STL_UNINITIALIZED_H
#include<typeinfo.h>
#include"stl_algobase.h"
template<class ForwardIterator, class Size, class T>
ForwardIterator __uninitialized_fill_n_aux(ForwardIterator first, Size n, const T &x, __true_type)
{
return fill_n(first, n, x);
}
template<class ForwardIterator, class Size, class T>
ForwardIterator __uninitialized_fill_n_aux(ForwardIterator first, Size n, const T &x, __false_type)
{
ForwardIterator cur = first;
for(; n>0; --n, ++cur)
construct(&*cur, x);
return cur;
}
template<class ForwardIterator, class Size, class T, class T1>
ForwardIterator __uninitialized_fill_n(ForwardIterator first, Size n, const T &x, T1*)
{
cout<<"T1 = "<<typeid(T1).name()<<endl;
typedef typename __type_traits<T1>::is_POD_type is_POD;
return __uninitialized_fill_n_aux(first, n, x, is_POD());
}
template<class ForwardIterator, class Size, class T>
ForwardIterator uninitialized_fill_n(ForwardIterator first, Size n, const T &x)
{
return __uninitialized_fill_n(first, n, x, value_type(first));
}
///////////////////////////////////////////////////////////////////////////////
template <class InputIterator, class ForwardIterator>
inline ForwardIterator __uninitialized_copy_aux(InputIterator first,
InputIterator last,
ForwardIterator result,
__true_type)
{
return copy(first, last, result);
}
template <class InputIterator, class ForwardIterator>
ForwardIterator __uninitialized_copy_aux(InputIterator first,
InputIterator last,
ForwardIterator result,
__false_type)
{
ForwardIterator cur = result;
for ( ; first != last; ++first, ++cur)
construct(&*cur, *first);
return cur;
}
template <class InputIterator, class ForwardIterator, class T>
inline ForwardIterator __uninitialized_copy(InputIterator first,
InputIterator last,
ForwardIterator result, T*)
{
typedef typename __type_traits<T>::is_POD_type is_POD;
return __uninitialized_copy_aux(first, last, result, is_POD());
}
template <class InputIterator, class ForwardIterator>
inline ForwardIterator uninitialized_copy(InputIterator first,
InputIterator last,
ForwardIterator result)
{
return __uninitialized_copy(first, last, result, value_type(result));
}
#endif
stl_alloc.h 空間配置器
#ifndef _STL_ALLOC_H
#define _STL_ALLOC_H
#if 0
#include<new>
#define __THROW_BAD_ALLOC throw bad_alloc
#else
#include<iostream.h>
#include<malloc.h>
#include<stdlib.h>
#define __THROW_BAD_ALLOC cerr<<"Out Of Memory."<<endl;exit(1)
#endif
//malloc free
template<int inst>
class __malloc_alloc_template
{
private:
static void* oom_malloc(size_t n)
{
void (*my_malloc_handler)();
void *result;
for(;;)
{
my_malloc_handler = __malloc_alloc_oom_handler;
if(0 == my_malloc_handler)
{
__THROW_BAD_ALLOC;
}
(*my_malloc_handler)();
result = malloc(n);
if(result)
return result;
}
}
static void* oom_realloc(void *p, size_t n)
{
void (* my_malloc_handler)();
void *result;
for (;;)
{
my_malloc_handler = __malloc_alloc_oom_handler;
if (0 == my_malloc_handler)
{
__THROW_BAD_ALLOC;
}
(*my_malloc_handler)();
result = realloc(p, n);
if (result)
return(result);
}
}
static void(*__malloc_alloc_oom_handler)();
public:
static void* allocate(size_t n)
{
void *result = malloc(n);
if(0 == result)
result = oom_malloc(n);
return result;
}
static void deallocate(void *p, size_t n)
{
free(p);
}
static void* reallocate(void *p, size_t old_sz, size_t new_sz)
{
void *result = realloc(p, new_sz);
if(0 == result)
result = oom_realloc(p, new_sz);
return result;
}
public:
//set_new_handler 模擬
static void(*set_malloc_handler(void(*f)()))()
{
void(*old)() = __malloc_alloc_oom_handler;
__malloc_alloc_oom_handler = f;
return old;
}
};
void(* __malloc_alloc_template<0>::__malloc_alloc_oom_handler)() = 0;
typedef __malloc_alloc_template<0> malloc_alloc;
/////////////////////////////////////////////////////////////////////////////////
enum {__ALIGN = 8};
enum {__MAX_BYTES = 128};
enum {__NFREELISTS = __MAX_BYTES / __ALIGN};
template<bool threads, int inst>
class __default_alloc_template
{
public:
static void * allocate(size_t n);
static void deallocate(void *p, size_t n);
static void * reallocate(void *p, size_t old_sz, size_t new_sz);
protected:
static void * refill(size_t n);
static char* chunk_alloc(size_t size, int &nobjs);
private:
static size_t ROUND_UP(size_t bytes)
{
return ((bytes + __ALIGN-1) &~(__ALIGN-1));
}
private:
union obj
{
union obj * free_list_link;
char client_data[1];
};
private:
static size_t FREELIST_INDEX(size_t bytes)
{
return ((bytes + __ALIGN-1) / __ALIGN-1);
}
static obj* free_list[__NFREELISTS];
private:
static char * start_free;
static char * end_free;
static size_t heap_size;
};
template<bool threads, int inst>
char* __default_alloc_template<threads, inst>::start_free = 0;
template<bool threads, int inst>
char* __default_alloc_template<threads, inst>::end_free = 0;
template<bool threads, int inst>
size_t __default_alloc_template<threads, inst>::heap_size = 0;
template<bool threads, int inst>
__default_alloc_template<threads, inst>::obj*
__default_alloc_template<threads, inst>::free_list[__NFREELISTS] =
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
template<bool threads, int inst>
void * __default_alloc_template<threads, inst>::allocate(size_t n)
{
obj ** my_free_list;
obj * result;
if(n > __MAX_BYTES)
return malloc_alloc::allocate(n);
my_free_list = free_list + FREELIST_INDEX(n);
result = *my_free_list;
if(result == 0)
{
void *r = refill(ROUND_UP(n));
return r;
}
*my_free_list = result->free_list_link;
return result;
}
template <bool threads, int inst>
char*
__default_alloc_template<threads, inst>::chunk_alloc(size_t size, int& nobjs)
{
char * result;
size_t total_bytes = size * nobjs;
size_t bytes_left = end_free - start_free;
if (bytes_left >= total_bytes)
{
result = start_free;
start_free += total_bytes;
return(result);
}
else if (bytes_left >= size)
{
nobjs = bytes_left/size;
total_bytes = size * nobjs;
result = start_free;
start_free += total_bytes;
return(result);
}
else
{
size_t bytes_to_get = 2 * total_bytes + ROUND_UP(heap_size >> 4);
if (bytes_left > 0)
{
obj ** my_free_list = free_list + FREELIST_INDEX(bytes_left);
((obj *)start_free) -> free_list_link = *my_free_list;
*my_free_list = (obj *)start_free;
}
start_free = (char *)malloc(bytes_to_get);
if (0 == start_free)
{
int i;
obj ** my_free_list, *p;
for (i = size; i <= __MAX_BYTES; i += __ALIGN)
{
my_free_list = free_list + FREELIST_INDEX(i);
p = *my_free_list;
if (0 != p)
{
*my_free_list = p -> free_list_link;
start_free = (char *)p;
end_free = start_free + i;
return(chunk_alloc(size, nobjs));
}
}
end_free = 0;
start_free = (char *)malloc_alloc::allocate(bytes_to_get);
}
heap_size += bytes_to_get;
end_free = start_free + bytes_to_get;
return(chunk_alloc(size, nobjs));
}
}
template <bool threads, int inst>
void* __default_alloc_template<threads, inst>::refill(size_t n)
{
int nobjs = 20;
char * chunk = chunk_alloc(n, nobjs);
obj ** my_free_list;
obj * result;
obj * current_obj, * next_obj;
int i;
if (1 == nobjs) return(chunk);
my_free_list = free_list + FREELIST_INDEX(n);
result = (obj *)chunk;
*my_free_list = next_obj = (obj *)(chunk + n);
for (i = 1; ; i++)
{
current_obj = next_obj;
next_obj = (obj *)((char *)next_obj + n);
if (nobjs - 1 == i)
{
current_obj -> free_list_link = 0;
break;
}
else
{
current_obj -> free_list_link = next_obj;
}
}
return(result);
}
template <bool threads, int inst>
void*
__default_alloc_template<threads, inst>::reallocate(void *p,
size_t old_sz,
size_t new_sz)
{
void * result;
size_t copy_sz;
if (old_sz > (size_t) __MAX_BYTES && new_sz > (size_t) __MAX_BYTES)
{
return(realloc(p, new_sz));
}
if (ROUND_UP(old_sz) == ROUND_UP(new_sz))
return(p);
result = allocate(new_sz);
copy_sz = new_sz > old_sz? old_sz : new_sz;
memcpy(result, p, copy_sz);
deallocate(p, old_sz);
return(result);
}
template <bool threads, int inst>
void __default_alloc_template<threads, inst>::deallocate(void *p, size_t n)
{
obj *q = (obj *)p;
obj ** my_free_list;
if (n > (size_t) __MAX_BYTES)
{
malloc_alloc::deallocate(p, n);
return;
}
my_free_list = free_list + FREELIST_INDEX(n);
q -> free_list_link = *my_free_list;
*my_free_list = q;
}
/////////////////////////////////////////////////////////////////
#ifdef __USE_MALLOC
typedef __malloc_alloc_template<0> malloc_alloc;
typedef malloc_alloc alloc;
#else
typedef __default_alloc_template<0,0> alloc;
#endif
template<class T, class Alloc>
class simple_alloc
{
public:
static T * allocate(size_t n)
{
return 0==n ? 0 : (T*)Alloc::allocate(n * sizeof(T));
}
static T * allocate(void)
{
return (T*)Alloc::allocate(sizeof(T));
}
static void deallocate(T *p, size_t n)
{
if(0!=n)
Alloc::deallocate(p, n*sizeof(T));
}
static void deallocate(T *p)
{
Alloc::deallocate(p,sizeof(T));
}
};
#endif
stl_deque.h 雙端佇列的實現
#ifndef _STL_DEQUE_H
#define _STL_DEQUE_H
template<class T>
T max(T &a, T &b)
{
return a > b ? a : b;
}
size_t __deque_buf_size(size_t n, size_t sz)
{
return n!=0 ? n : (sz<512 ? size_t(512/sz) : size_t(1));
}
template<class T, class Ref, class Ptr, size_t BufSiz>
struct __deque_iterator
{
typedef __deque_iterator<T, T&, T*, BufSiz> iterator;
typedef T value_type;
typedef Ptr pointer;
typedef Ref reference;
typedef size_t size_type;
typedef size_t difference_type;
typedef T** map_pointer;
typedef __deque_iterator self;
static size_t buffer_size()
{
return __deque_buf_size(BufSiz, sizeof(T));
}
T *cur;
T *first;
T *last;
map_pointer node; //T**node
/////////////////////////////////////////////////////////
__deque_iterator() : cur(0), first(0), last(0), node(0)
{}
void set_node(map_pointer new_node)
{
node = new_node;
first = *new_node;
last = first + difference_type(buffer_size());
}
bool operator==(const self& x) const { return cur == x.cur; }
bool operator!=(const self& x) const { return !(*this == x); }
reference operator*() const { return *cur; }
self& operator++()
{
++cur;
if (cur == last)
{
set_node(node + 1);
cur = first;
}
return *this;
}
};
template<class T, class Alloc=alloc, size_t BufSiz=0>
class deque
{
public:
typedef T value_type;
typedef size_t size_type;
typedef value_type* pointer;
typedef __deque_iterator<T, T&, T*, BufSiz> iterator;
public:
deque() : start(), finish(), map(0), map_size(0)
{
create_map_and_nodes(0);
}
public:
iterator begin()
{
return start;
}
iterator end()
{
return finish;
}
public:
void push_back(const value_type& t)
{
if (finish.cur != finish.last - 1)
{
construct(finish.cur, t);
++finish.cur;
}
else
push_back_aux(t);
}
void push_front(const value_type& t)
{
if (start.cur != start.first)
{
construct(start.cur - 1, t);
--start.cur;
}
else
push_front_aux(t);
}
protected:
void push_back_aux(const value_type& t);
void push_front_aux(const value_type& t);
void reserve_map_at_back (size_type nodes_to_add = 1)
{
if (nodes_to_add + 1 > map_size - (finish.node - map))
reallocate_map(nodes_to_add, false);
}
void reserve_map_at_front (size_type nodes_to_add = 1)
{
if (nodes_to_add > start.node - map)
reallocate_map(nodes_to_add, true);
}
void reallocate_map(size_type nodes_to_add, bool add_at_front);
protected:
void create_map_and_nodes(size_type n);
static size_type initial_map_size()
{
return 8;
}
static size_type buffer_size()
{
return __deque_buf_size(BufSiz, sizeof(value_type));
}
pointer allocate_node()
{
return data_allocator::allocate(buffer_size());
}
protected:
typedef pointer* map_pointer;
typedef simple_alloc<value_type, Alloc> data_allocator;
typedef simple_alloc<pointer, Alloc> map_allocator;
protected:
iterator start;
iterator finish;
map_pointer map;
size_type map_size;
};
template <class T, class Alloc, size_t BufSize>
void deque<T, Alloc, BufSize>::create_map_and_nodes(size_type num_elements)
{
size_type num_nodes = num_elements / buffer_size() + 1;
//map_size = max(initial_map_size(), num_nodes + 2);
map_size = initial_map_size() > (num_nodes + 2) ? initial_map_size() : (num_nodes + 2);
map = map_allocator::allocate(map_size);
map_pointer nstart = map + (map_size - num_nodes) / 2;
map_pointer nfinish = nstart + num_nodes - 1;
map_pointer cur;
for (cur = nstart; cur <= nfinish; ++cur)
*cur = allocate_node();
start.set_node(nstart);
finish.set_node(nfinish);
start.cur = start.first;
finish.cur = finish.first + num_elements % buffer_size();
}
template <class T, class Alloc, size_t BufSize>
void deque<T, Alloc, BufSize>::push_back_aux(const value_type& t)
{
value_type t_copy = t;
reserve_map_at_back();
*(finish.node + 1) = allocate_node();
construct(finish.cur, t_copy);
finish.set_node(finish.node + 1);
finish.cur = finish.first;
}
template <class T, class Alloc, size_t BufSize>
void deque<T, Alloc, BufSize>::push_front_aux(const value_type& t)
{
value_type t_copy = t;
reserve_map_at_front();
*(start.node - 1) = allocate_node();
start.set_node(start.node - 1);
start.cur = start.last - 1;
construct(start.cur, t_copy);
}
template <class T, class Alloc, size_t BufSize>
void deque<T, Alloc, BufSize>::reallocate_map(size_type nodes_to_add,
bool add_at_front)
{
size_type old_num_nodes = finish.node - start.node + 1;
size_type new_num_nodes = old_num_nodes + nodes_to_add;
map_pointer new_nstart;
if (map_size > 2 * new_num_nodes)
{
new_nstart = map + (map_size - new_num_nodes) / 2
+ (add_at_front ? nodes_to_add : 0);
if (new_nstart < start.node)
copy(start.node, finish.node + 1, new_nstart);
else
copy_backward(start.node, finish.node + 1, new_nstart + old_num_nodes);
}
else
{
size_type new_map_size = map_size + max(map_size, nodes_to_add) + 2;
map_pointer new_map = map_allocator::allocate(new_map_size);
new_nstart = new_map + (new_map_size - new_num_nodes) / 2
+ (add_at_front ? nodes_to_add : 0);
copy(start.node, finish.node + 1, new_nstart);
map_allocator::deallocate(map, map_size);
map = new_map;
map_size = new_map_size;
}
start.set_node(new_nstart);
finish.set_node(new_nstart + old_num_nodes - 1);
}
#endif
測試主函式main.cpp
void main()
{
deque<int> de;
de.push_back(1);
de.push_back(2);
de.push_front(3);
de.push_front(4); //4 3 1 2
deque<int>::iterator it = de.begin();
while(it != de.end())
{
cout<<*it<<" ";
++it;
}
cout<<endl;
}
參考文獻:《STL原始碼剖析》
相關推薦
STL原始碼剖析之stl_deque的實現(二)
STL中deque(雙端佇列)是一種非常重要的結構,stack,與queue底層都是藉助deque. deque(雙端佇列)是一種雙向開口的連續性空間,雙向開口意思是可以在頭尾兩端做元素的插入和刪除操作。deque和vector最大的差異在於deque允許常數時間內對起頭端
mybatis原始碼解析之Configuration載入(二)
概述 上一篇我們講了configuation.xml中幾個標籤的解析,例如<properties>,<typeAlises>,<settings>等,今天我們來介紹剩下的兩個比較重要的標籤之一,<environments>,這個標籤主要用於我們訪問資料庫的配置
elasticsearch原始碼分析之啟動過程(二)
最近開始廣泛的使用elasticsearch,也開始寫一些java程式碼了,為了提高java程式碼能力,也為了更加深入一點了解elasticsearch的內部運作機制,所以開始看一些elasticsearch的原始碼了。對於這種廣受追捧的開源專案,細細品讀一定會受益匪淺,
Java併發包原始碼學習之AQS框架(二)CLH lock queue和自旋鎖
上一篇文章提到AQS是基於CLH lock queue,那麼什麼是CLH lock queue,說複雜很複雜說簡單也簡單, 所謂大道至簡: CLH lock queue其實就是一個FIFO的佇列,佇列中的每個結點(執行緒)只要等待其前繼釋放鎖就可以了。 AbstractQueuedSynchronizer
雲客Drupal8原始碼分析之實體Entity(二)配置實體基類
配置實體基類是系統定義的一個用於配置實體的抽象基類,繼承自實體基類,完成了配置實體的大部分通用功能,具體的配置實體往往會繼承它,比如使用者角色實體,這樣寫少量程式碼即可,類定義如下: Drupal\Core\Config\Entity\ConfigEntityBase 實
Android4.4.2原始碼分析之WiFi模組(二)
接著上一篇繼續對WiFi原始碼的分析 onResume方法中 6>,首先是呼叫WiFiEnabler的resume方法對switch進行管理 接下來註冊廣播 getActivity().registerReceiver(mReceiver, mFilter);
spring原始碼解析之IOC容器(二)------載入和註冊
上一篇跟蹤了IOC容器對配置檔案的定位,現在我們繼續跟蹤程式碼,看看IOC容器是怎麼載入和註冊配置檔案中的資訊的。開始之前,首先我們先來了解一下IOC容器所使用的資料結構-------BeanDefinition,它是一個上層介面,有很多實現類,分別對應不同的資料載體。我們平時開發的時候,也會定義很多po
Spring原始碼解析之基礎應用(二)
方法注入 在spring容器中,大部分bean的作用域(scope)是單例(singleton)的,少部分bean的作用域是原型(prototype),如果一個bean的作用域是原型,我們A bean的作用域是原型,B bean中以@Autowired的方式注入A,那麼B在A中依舊是單例。我們可以讓B類實現A
【原始碼剖析】tornado-memcached-sessions —— Tornado session 支援的實現(二)
客官您終於回頭了!讓我們本著探(zuo)索(si)精神把 session.py 看完吧... 首先看看需要的庫: pickle 一個用於序列化反序列化的庫(聽
C++之STL中sort函式的內部實現(二)
另外一個版本: 概述 先進行introsort,基本有序後再使用insertion sort。introsort是改進的quick sort,為了防止最壞情況發生,它使用__lg()函式控制分割惡化的情況。 intro sort演算法 元素個數
併發程式設計(十二)—— Java 執行緒池 實現原理與原始碼深度解析 之submit方法 (二)
在上一篇《併發程式設計(十一)—— Java 執行緒池 實現原理與原始碼深度解析(一)》中提到了執行緒池ThreadPoolExecutor的原理以及它的execute方法。這篇文章是接著上一篇文章寫的,如果你沒有閱讀上一篇文章,建議你去讀讀。本文解析ThreadPoolExecutor#submit。
Spring原始碼分析之IOC的三種常見用法及原始碼實現(二)
Spring原始碼分析之IOC的三種常見用法及原始碼實現(二) 回顧上文 我們研究的是 AnnotationConfigApplicationContext annotationConfigApplication = new AnnotationConfigApplicationContext
STL原始碼剖析——stack的實現原理和使用方法詳解
Stack 簡介 stack 是堆疊容器,是一種“先進後出”的容器。 stack 是簡單地裝飾 deque 容器而成為另外一種容器。 使用 stack 時需要加上標頭檔案 #include<s
STL原始碼剖析——deque的實現原理和使用方法詳解
Deque 簡介 deque是“double—ended queue”的縮寫,和vector一樣都是STL的容器,deque 是雙端陣列,而 vector 是單端的。 deque 在介面上和 vector 非常相似,在許多操作的地方
spring-boot-admin原始碼分析及單機監控spring-boot-monitor的實現(二)
SpringBootMonitor spring-boot-admin原始碼分析及單機監控spring-boot-monitor的實現(一) spring-boot-admin原始碼分析及單機監控spring-boot-monitor的實現(二)
嵌入式核心及驅動開發之學習筆記(二) 實現應用控制驅動
Linux系統根據驅動程式實現的模型框架將裝置驅動分成字元裝置驅動、塊裝置驅動、網路裝置驅動三大類。這裡簡單理解一下概念 字元裝置:裝置按位元組流處理資料,通常用的串列埠裝置、鍵盤裝置都是這種。 塊裝置:裝置按塊單位對資料處理,通常是儲存裝置。 網路裝置:顧名思義,建立在soc
STL原始碼剖析之map和set
之前分析二叉搜尋樹和平衡二叉樹時,真心感覺樹的實現真是難,特別是平衡二叉樹,不平衡之後需要調整,還要考慮各種情況,累感不愛.今天看到這個紅黑樹,發現比平衡二叉樹還難,但是紅黑樹比平衡二叉樹使用的場景更多,所以平常使用時,我們需要了解紅黑樹的實現原理,如果有能力,可以自己實現,但是如果實在做不出來,也
Android底部導航欄實現(二)之RadioGroup
這裡簡單記錄一下Android底部導航欄通過RadioGroup+Fragment的實現。 這裡寫圖片描述 佈局: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:and
Html靜態網頁的實現——(二)之傻瓜式教程
上次說到Html5中無法換行的問題 <body> <p>把文字輸入到這裡</p> <p>把文字輸入到這裡</p> </body> 看看執行結果 這下是不是就換行了 格式:<p a
以太坊原始碼分析之 P2P網路(二、節點發現流程)
區塊鏈特輯 :https://blog.csdn.net/fusan2004/article/details/80879343,歡迎查閱,原創作品,轉載請標明!上一篇文章簡單介紹了下一些基礎的型別定義,從這一篇開始我們將描述p2p網路的更多細節。從關於節點的定義來看,其實不同